diff --git a/intern/ghost/intern/GHOST_ContextVK.cc b/intern/ghost/intern/GHOST_ContextVK.cc index b97ae8d5830..866794eebce 100644 --- a/intern/ghost/intern/GHOST_ContextVK.cc +++ b/intern/ghost/intern/GHOST_ContextVK.cc @@ -219,6 +219,7 @@ class GHOST_DeviceVK { device_features.dualSrcBlend = VK_TRUE; device_features.logicOp = VK_TRUE; device_features.imageCubeArray = VK_TRUE; + device_features.multiViewport = VK_TRUE; #endif VkDeviceCreateInfo device_create_info = {}; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 5d8670f4ba8..a16b7c923e3 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -571,6 +571,7 @@ set(GLSL_SRC_TEST tests/shaders/gpu_compute_ssbo_test.glsl tests/shaders/gpu_compute_vbo_test.glsl tests/shaders/gpu_compute_dummy_test.glsl + tests/shaders/gpu_framebuffer_layer_viewport_test.glsl tests/shaders/gpu_push_constants_test.glsl ) diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 4d7e7755648..bee58653838 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -35,6 +35,9 @@ typedef enum eGPUFrameBufferBits { ENUM_OPERATORS(eGPUFrameBufferBits, GPU_STENCIL_BIT) +/* Guaranteed by the spec and is never greater than 16 on any hardware or implementation. */ +#define GPU_MAX_VIEWPORTS 16 + #ifdef __cplusplus extern "C" { #endif @@ -340,10 +343,23 @@ void GPU_framebuffer_default_size(GPUFrameBuffer *framebuffer, int width, int he * or when binding the frame-buffer after modifying its attachments. * * \note Viewport and scissor size is stored per frame-buffer. + * \note Setting a singular viewport will only change the state of the first viewport. + * \note Must be called after first bind. */ void GPU_framebuffer_viewport_set( GPUFrameBuffer *framebuffer, int x, int y, int width, int height); +/** + * Similar to `GPU_framebuffer_viewport_set()` but specify the bounds of all 16 viewports. + * By default geometry renders only to the first viewport. That can be changed by setting + * `gpu_ViewportIndex` in the vertex. + * + * \note Viewport and scissor size is stored per frame-buffer. + * \note Must be called after first bind. + */ +void GPU_framebuffer_multi_viewports_set(GPUFrameBuffer *gpu_fb, + const int viewport_rects[GPU_MAX_VIEWPORTS][4]); + /** * Return the viewport offset and size in a int quadruple: (x, y, width, height). * \note Viewport and scissor size is stored per frame-buffer. diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index 35fb841d80b..dba4897f2ea 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -391,6 +391,12 @@ void GPU_framebuffer_viewport_set(GPUFrameBuffer *gpu_fb, int x, int y, int widt unwrap(gpu_fb)->viewport_set(viewport_rect); } +void GPU_framebuffer_multi_viewports_set(GPUFrameBuffer *gpu_fb, + const int viewport_rects[GPU_MAX_VIEWPORTS][4]) +{ + unwrap(gpu_fb)->viewport_multi_set(viewport_rects); +} + void GPU_framebuffer_viewport_get(GPUFrameBuffer *gpu_fb, int r_viewport[4]) { unwrap(gpu_fb)->viewport_get(r_viewport); diff --git a/source/blender/gpu/intern/gpu_framebuffer_private.hh b/source/blender/gpu/intern/gpu_framebuffer_private.hh index b113006c82e..c33d8af3703 100644 --- a/source/blender/gpu/intern/gpu_framebuffer_private.hh +++ b/source/blender/gpu/intern/gpu_framebuffer_private.hh @@ -81,8 +81,9 @@ class FrameBuffer { /** Debug name. */ char name_[DEBUG_NAME_LEN]; /** Frame-buffer state. */ - int viewport_[4] = {0}; + int viewport_[GPU_MAX_VIEWPORTS][4] = {{0}}; int scissor_[4] = {0}; + bool multi_viewport_ = false; bool scissor_test_ = false; bool dirty_state_ = true; @@ -157,10 +158,22 @@ class FrameBuffer { inline void viewport_set(const int viewport[4]) { - if (!equals_v4v4_int(viewport_, viewport)) { - copy_v4_v4_int(viewport_, viewport); + if (!equals_v4v4_int(viewport_[0], viewport)) { + copy_v4_v4_int(viewport_[0], viewport); dirty_state_ = true; } + multi_viewport_ = false; + } + + inline void viewport_multi_set(const int viewports[GPU_MAX_VIEWPORTS][4]) + { + for (size_t i = 0; i < GPU_MAX_VIEWPORTS; i++) { + if (!equals_v4v4_int(viewport_[i], viewports[i])) { + copy_v4_v4_int(viewport_[i], viewports[i]); + dirty_state_ = true; + } + } + multi_viewport_ = true; } inline void scissor_set(const int scissor[4]) @@ -178,7 +191,7 @@ class FrameBuffer { inline void viewport_get(int r_viewport[4]) const { - copy_v4_v4_int(r_viewport, viewport_); + copy_v4_v4_int(r_viewport, viewport_[0]); } inline void scissor_get(int r_scissor[4]) const diff --git a/source/blender/gpu/intern/gpu_shader_create_info.hh b/source/blender/gpu/intern/gpu_shader_create_info.hh index bc2445462aa..8d237858632 100644 --- a/source/blender/gpu/intern/gpu_shader_create_info.hh +++ b/source/blender/gpu/intern/gpu_shader_create_info.hh @@ -178,6 +178,11 @@ enum class BuiltinBits { VERTEX_ID = (1 << 14), WORK_GROUP_ID = (1 << 15), WORK_GROUP_SIZE = (1 << 16), + /** + * Allow setting the target viewport when using multi viewport feature. + * \note Emulated through geometry shader on older hardware. + */ + VIEWPORT_INDEX = (1 << 17), /* Not a builtin but a flag we use to tag shaders that use the debug features. */ USE_DEBUG_DRAW = (1 << 29), diff --git a/source/blender/gpu/metal/mtl_framebuffer.mm b/source/blender/gpu/metal/mtl_framebuffer.mm index afb0d347a7a..f7b11eda21a 100644 --- a/source/blender/gpu/metal/mtl_framebuffer.mm +++ b/source/blender/gpu/metal/mtl_framebuffer.mm @@ -780,8 +780,8 @@ void MTLFrameBuffer::apply_state() /* Ensure viewport has been set. NOTE: This should no longer happen, but kept for safety to * track bugs. If viewport size is zero, use framebuffer size. */ - int viewport_w = viewport_[2]; - int viewport_h = viewport_[3]; + int viewport_w = viewport_[0][2]; + int viewport_h = viewport_[0][3]; if (viewport_w == 0 || viewport_h == 0) { MTL_LOG_WARNING("Viewport had width and height of (0,0) -- Updating -- DEBUG Safety check"); viewport_w = default_width_; @@ -789,7 +789,7 @@ void MTLFrameBuffer::apply_state() } /* Update Context State. */ - mtl_ctx->set_viewport(viewport_[0], viewport_[1], viewport_w, viewport_h); + mtl_ctx->set_viewport(viewport_[0][0], viewport_[0][1], viewport_w, viewport_h); mtl_ctx->set_scissor(scissor_[0], scissor_[1], scissor_[2], scissor_[3]); mtl_ctx->set_scissor_enabled(scissor_test_); diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 3de20a0fbf6..db2b9b82d20 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -592,7 +592,8 @@ void GLBackend::capabilities_init() GLContext::explicit_location_support = epoxy_gl_version() >= 43; GLContext::geometry_shader_invocations = epoxy_has_gl_extension("GL_ARB_gpu_shader5"); GLContext::fixed_restart_index_support = epoxy_has_gl_extension("GL_ARB_ES3_compatibility"); - GLContext::layered_rendering_support = epoxy_has_gl_extension("GL_AMD_vertex_shader_layer"); + GLContext::layered_rendering_support = epoxy_has_gl_extension( + "GL_ARB_shader_viewport_layer_array"); GLContext::native_barycentric_support = epoxy_has_gl_extension( "GL_AMD_shader_explicit_vertex_parameter"); GLContext::multi_bind_support = GLContext::multi_bind_image_support = epoxy_has_gl_extension( diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc index 5bbbf7f1a73..f2be3e1c3db 100644 --- a/source/blender/gpu/opengl/gl_framebuffer.cc +++ b/source/blender/gpu/opengl/gl_framebuffer.cc @@ -43,10 +43,10 @@ GLFrameBuffer::GLFrameBuffer( height_ = h; srgb_ = false; - viewport_[0] = scissor_[0] = 0; - viewport_[1] = scissor_[1] = 0; - viewport_[2] = scissor_[2] = w; - viewport_[3] = scissor_[3] = h; + viewport_[0][0] = scissor_[0] = 0; + viewport_[0][1] = scissor_[1] = 0; + viewport_[0][2] = scissor_[2] = w; + viewport_[0][3] = scissor_[3] = h; if (fbo_id_) { debug::object_label(GL_FRAMEBUFFER, fbo_id_, name_); @@ -230,7 +230,20 @@ void GLFrameBuffer::apply_state() return; } - glViewport(UNPACK4(viewport_)); + if (multi_viewport_ == false) { + glViewport(UNPACK4(viewport_[0])); + } + else { + /* Great API you have there! You have to convert to float values for setting int viewport + * values. **Audible Facepalm** */ + float viewports_f[GPU_MAX_VIEWPORTS][4]; + for (int i = 0; i < GPU_MAX_VIEWPORTS; i++) { + for (int j = 0; j < 4; j++) { + viewports_f[i][j] = viewport_[i][j]; + } + } + glViewportArrayv(0, GPU_MAX_VIEWPORTS, viewports_f[0]); + } glScissor(UNPACK4(scissor_)); if (scissor_test_) { diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 014a35237c6..6732aed2955 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -551,6 +551,10 @@ std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) con if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::LAYER)) { ss << "out int gpu_Layer;\n"; } + if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::VIEWPORT_INDEX)) + { + ss << "out int gpu_ViewportIndex;\n"; + } if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) { if (!GLContext::native_barycentric_support) { /* Disabled or unsupported. */ @@ -584,6 +588,13 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c for (const StageInterfaceInfo *iface : in_interfaces) { print_interface(ss, "in", *iface); } + if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::LAYER)) { + ss << "#define gpu_Layer gl_Layer\n"; + } + if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::VIEWPORT_INDEX)) + { + ss << "#define gpu_ViewportIndex gl_ViewportIndex\n"; + } if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) { if (!GLContext::native_barycentric_support) { ss << "flat in vec4 gpu_pos[3];\n"; @@ -736,6 +747,8 @@ std::string GLShader::workaround_geometry_shader_source_create( const bool do_layer_workaround = !GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::LAYER); + const bool do_viewport_workaround = !GLContext::layered_rendering_support && + bool(info.builtins_ & BuiltinBits::VIEWPORT_INDEX); const bool do_barycentric_workaround = !GLContext::native_barycentric_support && bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD); @@ -752,6 +765,9 @@ std::string GLShader::workaround_geometry_shader_source_create( if (do_layer_workaround) { ss << "in int gpu_Layer[];\n"; } + if (do_viewport_workaround) { + ss << "in int gpu_ViewportIndex[];\n"; + } if (do_barycentric_workaround) { ss << "flat out vec4 gpu_pos[3];\n"; ss << "smooth out vec3 gpu_BaryCoord;\n"; @@ -764,6 +780,9 @@ std::string GLShader::workaround_geometry_shader_source_create( if (do_layer_workaround) { ss << " gl_Layer = gpu_Layer[0];\n"; } + if (do_viewport_workaround) { + ss << " gl_ViewportIndex = gpu_ViewportIndex[0];\n"; + } if (do_barycentric_workaround) { ss << " gpu_pos[0] = gl_in[0].gl_Position;\n"; ss << " gpu_pos[1] = gl_in[1].gl_Position;\n"; @@ -796,6 +815,9 @@ bool GLShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info if (!GLContext::layered_rendering_support && bool(builtins & BuiltinBits::LAYER)) { return true; } + if (!GLContext::layered_rendering_support && bool(builtins & BuiltinBits::VIEWPORT_INDEX)) { + return true; + } return false; } @@ -853,8 +875,9 @@ static char *glsl_patch_default_get() STR_CONCAT(patch, slen, "#extension GL_ARB_shading_language_420pack: enable\n"); } if (GLContext::layered_rendering_support) { - STR_CONCAT(patch, slen, "#extension GL_AMD_vertex_shader_layer: enable\n"); + STR_CONCAT(patch, slen, "#extension GL_ARB_shader_viewport_layer_array: enable\n"); STR_CONCAT(patch, slen, "#define gpu_Layer gl_Layer\n"); + STR_CONCAT(patch, slen, "#define gpu_ViewportIndex gl_ViewportIndex\n"); } if (GLContext::native_barycentric_support) { STR_CONCAT(patch, slen, "#extension GL_AMD_shader_explicit_vertex_parameter: enable\n"); diff --git a/source/blender/gpu/tests/framebuffer_test.cc b/source/blender/gpu/tests/framebuffer_test.cc index b78fcc44d7c..03682b76c97 100644 --- a/source/blender/gpu/tests/framebuffer_test.cc +++ b/source/blender/gpu/tests/framebuffer_test.cc @@ -6,10 +6,13 @@ #include "GPU_context.h" #include "GPU_framebuffer.h" +#include "GPU_shader.h" #include "gpu_testing.hh" #include "BLI_math_vector.hh" +#include "gpu_shader_create_info.hh" + namespace blender::gpu::tests { static void test_framebuffer_clear_color_single_attachment() @@ -248,4 +251,77 @@ static void test_framebuffer_cube() } GPU_TEST(framebuffer_cube) +/* Effectively tests the same way EEVEE-Next shadows are rendered. */ +static void test_framebuffer_multi_viewport() +{ + using namespace gpu::shader; + + GPU_render_begin(); + + const int2 size(4, 4); + const int layers = 256; + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; + GPUTexture *texture = GPU_texture_create_2d_array( + __func__, UNPACK2(size), layers, 1, GPU_RG32I, usage, nullptr); + + GPUFrameBuffer *framebuffer = GPU_framebuffer_create(__func__); + GPU_framebuffer_ensure_config(&framebuffer, + {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(texture)}); + GPU_framebuffer_bind(framebuffer); + + int viewport_rects[16][4]; + for (int i = 0; i < 16; i++) { + viewport_rects[i][0] = i % 4; + viewport_rects[i][1] = i / 4; + viewport_rects[i][2] = 1; + viewport_rects[i][3] = 1; + } + GPU_framebuffer_multi_viewports_set(framebuffer, viewport_rects); + + const float4 clear_color(0.0f); + GPU_framebuffer_clear_color(framebuffer, clear_color); + + ShaderCreateInfo create_info(""); + create_info.vertex_source("gpu_framebuffer_layer_viewport_test.glsl"); + create_info.fragment_source("gpu_framebuffer_layer_viewport_test.glsl"); + create_info.builtins(BuiltinBits::VIEWPORT_INDEX | BuiltinBits::LAYER); + create_info.fragment_out(0, Type::IVEC2, "out_value"); + + GPUShader *shader = GPU_shader_create_from_info( + reinterpret_cast(&create_info)); + + /* TODO(fclem): remove this boilerplate. */ + GPUVertFormat format{}; + GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_U32, 1, GPU_FETCH_INT); + GPUVertBuf *verts = GPU_vertbuf_create_with_format(&format); + GPU_vertbuf_data_alloc(verts, 3); + GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_TRIS, verts, nullptr, GPU_BATCH_OWNS_VBO); + + GPU_batch_set_shader(batch, shader); + + int tri_count = size.x * size.y * layers; + GPU_batch_draw_advanced(batch, 0, tri_count * 3, 0, 1); + + GPU_batch_discard(batch); + + GPU_finish(); + + int2 *read_data = static_cast(GPU_texture_read(texture, GPU_DATA_INT, 0)); + for (auto layer : IndexRange(layers)) { + for (auto viewport : IndexRange(16)) { + int2 expected_color(layer, viewport); + int2 pixel_color = read_data[viewport + layer * 16]; + EXPECT_EQ(pixel_color, expected_color); + } + } + MEM_freeN(read_data); + + GPU_framebuffer_free(framebuffer); + GPU_texture_free(texture); + GPU_shader_free(shader); + + GPU_render_end(); +} +GPU_TEST(framebuffer_multi_viewport) + } // namespace blender::gpu::tests diff --git a/source/blender/gpu/tests/shaders/gpu_framebuffer_layer_viewport_test.glsl b/source/blender/gpu/tests/shaders/gpu_framebuffer_layer_viewport_test.glsl new file mode 100644 index 00000000000..daa74daeaf6 --- /dev/null +++ b/source/blender/gpu/tests/shaders/gpu_framebuffer_layer_viewport_test.glsl @@ -0,0 +1,23 @@ + +#ifdef GPU_VERTEX_SHADER +void main() +{ + /* Fullscreen triangle. */ + int v = gl_VertexID % 3; + float x = -1.0 + float((v & 1) << 2); + float y = -1.0 + float((v & 2) << 1); + /* NOTE: Make it cover more than one viewport to test default scissors. */ + gl_Position = vec4(x * 2.0, y * 2.0, 1.0, 1.0); + + int index = gl_VertexID / 3; + gpu_ViewportIndex = index % 16; + gpu_Layer = index / 16; +} +#endif + +#ifdef GPU_FRAGMENT_SHADER +void main() +{ + out_value = ivec2(gpu_Layer, gpu_ViewportIndex); +} +#endif diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index e2ad98b3329..7b4138fdd5e 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -376,7 +376,7 @@ void VKCommandBuffer::ensure_active_framebuffer() render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; render_pass_begin_info.renderPass = state.framebuffer_->vk_render_pass_get(); render_pass_begin_info.framebuffer = state.framebuffer_->vk_framebuffer_get(); - render_pass_begin_info.renderArea = state.framebuffer_->vk_render_area_get(); + render_pass_begin_info.renderArea = state.framebuffer_->vk_render_areas_get()[0]; /* We don't use clear ops, but vulkan wants to have at least one. */ VkClearValue clear_value = {}; render_pass_begin_info.clearValueCount = 1; diff --git a/source/blender/gpu/vulkan/vk_framebuffer.cc b/source/blender/gpu/vulkan/vk_framebuffer.cc index 924fcf8875c..dd371a499ff 100644 --- a/source/blender/gpu/vulkan/vk_framebuffer.cc +++ b/source/blender/gpu/vulkan/vk_framebuffer.cc @@ -71,52 +71,53 @@ void VKFrameBuffer::bind(bool /*enabled_srgb*/) context.activate_framebuffer(*this); } -VkViewport VKFrameBuffer::vk_viewport_get() const +Array VKFrameBuffer::vk_viewports_get() const { - VkViewport viewport; - int viewport_rect[4]; - viewport_get(viewport_rect); + Array viewports(this->multi_viewport_ ? GPU_MAX_VIEWPORTS : 1); - viewport.x = viewport_rect[0]; - viewport.y = viewport_rect[1]; - viewport.width = viewport_rect[2]; - viewport.height = viewport_rect[3]; - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - /* - * Vulkan has origin to the top left, Blender bottom left. We counteract this by using a negative - * viewport when flip_viewport_ is set. This flips the viewport making any draw/blit use the - * correct orientation. - */ - if (flip_viewport_) { - viewport.y = height_ - viewport_rect[1]; - viewport.height = -viewport_rect[3]; + int index = 0; + for (VkViewport &viewport : viewports) { + viewport.x = viewport_[index][0]; + viewport.y = viewport_[index][1]; + viewport.width = viewport_[index][2]; + viewport.height = viewport_[index][3]; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + /* + * Vulkan has origin to the top left, Blender bottom left. We counteract this by using a + * negative viewport when flip_viewport_ is set. This flips the viewport making any draw/blit + * use the correct orientation. + */ + if (flip_viewport_) { + viewport.y = height_ - viewport_[index][1]; + viewport.height = -viewport_[index][3]; + } + index++; } - - return viewport; + return viewports; } -VkRect2D VKFrameBuffer::vk_render_area_get() const +Array VKFrameBuffer::vk_render_areas_get() const { - VkRect2D render_area = {}; + Array render_areas(this->multi_viewport_ ? GPU_MAX_VIEWPORTS : 1); - if (scissor_test_get()) { - int scissor_rect[4]; - scissor_get(scissor_rect); - render_area.offset.x = scissor_rect[0]; - render_area.offset.y = scissor_rect[1]; - render_area.extent.width = scissor_rect[2]; - render_area.extent.height = scissor_rect[3]; + for (VkRect2D &render_area : render_areas) { + if (scissor_test_get()) { + int scissor_rect[4]; + scissor_get(scissor_rect); + render_area.offset.x = scissor_rect[0]; + render_area.offset.y = scissor_rect[1]; + render_area.extent.width = scissor_rect[2]; + render_area.extent.height = scissor_rect[3]; + } + else { + render_area.offset.x = 0; + render_area.offset.y = 0; + render_area.extent.width = width_; + render_area.extent.height = height_; + } } - else { - render_area.offset.x = 0; - render_area.offset.y = 0; - render_area.extent.width = width_; - render_area.extent.height = height_; - } - - return render_area; + return render_areas; } bool VKFrameBuffer::check(char /*err_out*/[256]) @@ -170,7 +171,7 @@ void VKFrameBuffer::clear(const Vector &attachments) const return; } VkClearRect clear_rect = {}; - clear_rect.rect = vk_render_area_get(); + clear_rect.rect = vk_render_areas_get()[0]; clear_rect.baseArrayLayer = 0; clear_rect.layerCount = 1; diff --git a/source/blender/gpu/vulkan/vk_framebuffer.hh b/source/blender/gpu/vulkan/vk_framebuffer.hh index 7f6d1c44314..777067d4076 100644 --- a/source/blender/gpu/vulkan/vk_framebuffer.hh +++ b/source/blender/gpu/vulkan/vk_framebuffer.hh @@ -8,6 +8,7 @@ #pragma once +#include "BLI_array.hh" #include "BLI_math_vector.hh" #include "BLI_span.hh" #include "BLI_vector.hh" @@ -107,8 +108,8 @@ class VKFrameBuffer : public FrameBuffer { BLI_assert(vk_render_pass_ != VK_NULL_HANDLE); return vk_render_pass_; } - VkViewport vk_viewport_get() const; - VkRect2D vk_render_area_get() const; + Array vk_viewports_get() const; + Array vk_render_areas_get() const; VkImage vk_image_get() const { BLI_assert(vk_image_ != VK_NULL_HANDLE); diff --git a/source/blender/gpu/vulkan/vk_pipeline.cc b/source/blender/gpu/vulkan/vk_pipeline.cc index 6190a2becdf..5d016b1c032 100644 --- a/source/blender/gpu/vulkan/vk_pipeline.cc +++ b/source/blender/gpu/vulkan/vk_pipeline.cc @@ -164,12 +164,12 @@ void VKPipeline::finalize(VKContext &context, /* Viewport state. */ VkPipelineViewportStateCreateInfo viewport_state = {}; viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - VkViewport viewport = framebuffer.vk_viewport_get(); - viewport_state.pViewports = &viewport; - viewport_state.viewportCount = 1; - VkRect2D scissor = framebuffer.vk_render_area_get(); - viewport_state.pScissors = &scissor; - viewport_state.scissorCount = 1; + Array viewports = framebuffer.vk_viewports_get(); + viewport_state.pViewports = &viewports[0]; + viewport_state.viewportCount = viewports.size(); + Array scissors = framebuffer.vk_render_areas_get(); + viewport_state.pScissors = &scissors[0]; + viewport_state.scissorCount = scissors.size(); pipeline_create_info.pViewportState = &viewport_state; /* Multi-sample state. */ diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 34157e05072..f348de28b2a 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -500,6 +500,11 @@ static char *glsl_patch_get() STR_CONCAT(patch, slen, "#define gl_InstanceID gpu_InstanceIndex\n"); + /* TODO(fclem): This creates a validation error and should be already part of Vulkan 1.2. */ + STR_CONCAT(patch, slen, "#extension GL_ARB_shader_viewport_layer_array: enable\n"); + STR_CONCAT(patch, slen, "#define gpu_Layer gl_Layer\n"); + STR_CONCAT(patch, slen, "#define gpu_ViewportIndex gl_ViewportIndex\n"); + STR_CONCAT(patch, slen, "#define DFDX_SIGN 1.0\n"); STR_CONCAT(patch, slen, "#define DFDY_SIGN 1.0\n"); @@ -526,6 +531,7 @@ Vector VKShader::compile_glsl_to_spirv(Span sources, shaderc::Compiler &compiler = backend.get_shaderc_compiler(); shaderc::CompileOptions options; options.SetOptimizationLevel(shaderc_optimization_level_performance); + options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2); if (G.debug & G_DEBUG_GPU_RENDERDOC) { options.SetOptimizationLevel(shaderc_optimization_level_zero); options.SetGenerateDebugInfo();