From 258a1ca9cd78d3050e414d45a43421717a133856 Mon Sep 17 00:00:00 2001 From: Artem Kharytoniuk Date: Mon, 3 Apr 2017 14:40:32 +0300 Subject: [PATCH] Multitexture rendering prototyping. --- data/compile.bat | 5 + data/multi_texture.frag | 14 ++ data/multi_texture.vert | 27 +++ data/multi_texture_frag.spv | Bin 0 -> 868 bytes data/multi_texture_vert.spv | Bin 0 -> 1724 bytes data/single_texture.frag | 12 ++ data/single_texture.vert | 24 +++ data/{frag.spv => single_texture_frag.spv} | Bin data/{vert.spv => single_texture_vert.spv} | Bin src/engine/renderer/tr_shade.c | 9 +- src/engine/renderer/vk_demo.cpp | 183 +++++++++++++++++++-- src/engine/renderer/vk_demo.h | 8 +- 12 files changed, 263 insertions(+), 19 deletions(-) create mode 100644 data/compile.bat create mode 100644 data/multi_texture.frag create mode 100644 data/multi_texture.vert create mode 100644 data/multi_texture_frag.spv create mode 100644 data/multi_texture_vert.spv create mode 100644 data/single_texture.frag create mode 100644 data/single_texture.vert rename data/{frag.spv => single_texture_frag.spv} (100%) rename data/{vert.spv => single_texture_vert.spv} (100%) diff --git a/data/compile.bat b/data/compile.bat new file mode 100644 index 0000000..6d8d1ad --- /dev/null +++ b/data/compile.bat @@ -0,0 +1,5 @@ +%VULKAN_SDK%\Bin\glslangValidator.exe -V -o single_texture_vert.spv single_texture.vert +%VULKAN_SDK%\Bin\glslangValidator.exe -V -o single_texture_frag.spv single_texture.frag +%VULKAN_SDK%\Bin\glslangValidator.exe -V -o multi_texture_vert.spv multi_texture.vert +%VULKAN_SDK%\Bin\glslangValidator.exe -V -o multi_texture_frag.spv multi_texture.frag + diff --git a/data/multi_texture.frag b/data/multi_texture.frag new file mode 100644 index 0000000..983e7b6 --- /dev/null +++ b/data/multi_texture.frag @@ -0,0 +1,14 @@ +#version 450 + +layout(binding = 1) uniform sampler2D texture_sampler; +layout(binding = 2) uniform sampler2D texture_sampler2; + +layout(location = 0) in vec3 frag_color; +layout(location = 1) in vec2 frag_tex_coord; +layout(location = 2) in vec2 frag_tex_coord2; + +layout(location = 0) out vec4 out_color; + +void main() { + out_color = texture(texture_sampler, frag_tex_coord) * texture(texture_sampler2, frag_tex_coord2); +} diff --git a/data/multi_texture.vert b/data/multi_texture.vert new file mode 100644 index 0000000..21e372d --- /dev/null +++ b/data/multi_texture.vert @@ -0,0 +1,27 @@ +#version 450 + +layout(binding = 0) uniform Uniform_Buffer_Object { + mat4 model; + mat4 view; + mat4 proj; +} ubo; + +layout(location = 0) in vec3 in_position; +layout(location = 1) in vec3 in_color; +layout(location = 2) in vec2 in_tex_coord; +layout(location = 3) in vec2 in_tex_coord2; + +layout(location = 0) out vec3 frag_color; +layout(location = 1) out vec2 frag_tex_coord; +layout(location = 2) out vec2 frag_tex_coord2; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(in_position, 1.0); + frag_color = in_color; + frag_tex_coord = in_tex_coord; + frag_tex_coord2 = in_tex_coord2; +} diff --git a/data/multi_texture_frag.spv b/data/multi_texture_frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..d6370f03cde745ae124304f6981da1cffedff328 GIT binary patch literal 868 zcmZXR%}xSA5QJNB`4Qzu6hzd3-iaYgt}F-hA$?XttqW$&PJx8kSRTR=_>xQ_X?U^}av|z40;)ALCh^C=R4yM?Rgtr^{p-E~5F{ zY??TnJD!s0IaE;%aWa8lw7viQp&-|TroTNy;epfX@a*D|l%eH>Mjdi=oVx5c?<;2y z)X@Xq=jd4Hlf&oz@X-R_=j_Vg*AxogcN<%AT8az8da}0q*(W(W?CHNG&zAwe$#UKR z*3oOW>f%-haLV9X_JD|?I zLwV+*mw8=zYT)q6*%8>4z8UxOb`CvXLIU|)p=hqk&`XY{T^V{F#9~KH860rmv#%J9 gzNf7ijlSnVF&yxZY)(fpv#8xk2|EY-meOn44>Q#{g#Z8m literal 0 HcmV?d00001 diff --git a/data/multi_texture_vert.spv b/data/multi_texture_vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..d00578702546f9d728958d273c8463238d02cdea GIT binary patch literal 1724 zcmZ9LTT>H35QWEt4JgV*;hn?2O<`WcC zuIhzorrjm)kLhoJHyr>j$d+aIWe;R68Hww%XR@k(6|KLtLFC5t8|6kib3*u_7w;tb zmn0u1-vz}MJU+4PI31?hK>1aF9(<(CDXpIeX*bLJ@%xi*H_77W*XeGGWO=9H>5;T0w&3a8|N3>m54|kw(QPS0|M(`0#kEyC9QWB$x2*?}$D^J! zgPuK1qsQUzZF%&moChZFt<3V^&gOA;IS)+Usm$`=ERUM00j{l@>HVsV&v2uF9`oKX zKH|K+GUgqEsf~E+45s(Q?L2x}#`GG@%b$}9T|)?rzaX!swJuxK{@er1+g?_T{=?P9 zoYzVo+{=LZpMjefW^Q#EwXOwxQ9j?2F#mDvRqS2N3eJo(riH1C9&!el9>Uq4vjL;O z9DMe$_`G~-;669Bavy3$e^V0wI19H*z&>542|u_%6x*eN1PcGf3BCxIrNtg&2KTh-*@^;ujXX* zlODd3lD=J$!JB45J{tOHnnn5WKeZ1zOEU7{E$^y)@|d~hU6T)QdDrEW3y+3AuE?0d zN9|3o8iCXDk6R5K_cUEIaNK!E6JkcUWaOhKUYGsQzQk_JI3Eo)Guyi|-Y_-4R>#2T lthP1z%##>%1`}gGPi4%87&8Q0Y(qYCA;!GGe>9~RvcF!+ZdL#Q literal 0 HcmV?d00001 diff --git a/data/single_texture.frag b/data/single_texture.frag new file mode 100644 index 0000000..0bc0d1b --- /dev/null +++ b/data/single_texture.frag @@ -0,0 +1,12 @@ +#version 450 + +layout(binding = 1) uniform sampler2D texture_sampler; + +layout(location = 0) in vec3 frag_color; +layout(location = 1) in vec2 frag_tex_coord; + +layout(location = 0) out vec4 out_color; + +void main() { + out_color = texture(texture_sampler, frag_tex_coord); +} diff --git a/data/single_texture.vert b/data/single_texture.vert new file mode 100644 index 0000000..95eff89 --- /dev/null +++ b/data/single_texture.vert @@ -0,0 +1,24 @@ +#version 450 + +layout(binding = 0) uniform Uniform_Buffer_Object { + mat4 model; + mat4 view; + mat4 proj; +} ubo; + +layout(location = 0) in vec3 in_position; +layout(location = 1) in vec3 in_color; +layout(location = 2) in vec2 in_tex_coord; + +layout(location = 0) out vec3 frag_color; +layout(location = 1) out vec2 frag_tex_coord; + +out gl_PerVertex { + vec4 gl_Position; +}; + +void main() { + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(in_position, 1.0); + frag_color = in_color; + frag_tex_coord = in_tex_coord; +} diff --git a/data/frag.spv b/data/single_texture_frag.spv similarity index 100% rename from data/frag.spv rename to data/single_texture_frag.spv diff --git a/data/vert.spv b/data/single_texture_vert.spv similarity index 100% rename from data/vert.spv rename to data/single_texture_vert.spv diff --git a/src/engine/renderer/tr_shade.c b/src/engine/renderer/tr_shade.c index 07e49c8..de3e905 100644 --- a/src/engine/renderer/tr_shade.c +++ b/src/engine/renderer/tr_shade.c @@ -816,6 +816,9 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) if ( pStage->bundle[1].image[0] != 0 ) { DrawMultitextured( input, stage ); + + // VULKAN + vulkan_demo->render_tess_multi(pStage->bundle[0].image[0], pStage->bundle[1].image[0]); } else { @@ -834,6 +837,9 @@ static void RB_IterateStagesGeneric( shaderCommands_t *input ) // draw // R_DrawElements( input->numIndexes, input->indexes ); + + // VULKAN + vulkan_demo->render_tess(pStage->bundle[0].image[0]); } // allow skipping out to show just lightmaps during development if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap ) ) @@ -1183,9 +1189,6 @@ void RB_EndSurface( void ) { // tess.currentStageIteratorFunc(); - // VULKAN - vulkan_demo->render_tess(tess.shader->stages[0]->bundle[0].image[0]); - // // draw debugging stuff // diff --git a/src/engine/renderer/vk_demo.cpp b/src/engine/renderer/vk_demo.cpp index 699fc5a..a9d1f39 100644 --- a/src/engine/renderer/vk_demo.cpp +++ b/src/engine/renderer/vk_demo.cpp @@ -28,10 +28,7 @@ struct Vertex { glm::vec3 pos; glm::vec3 color; glm::vec2 tex_coord; - - bool operator==(const Vertex& other) const { - return pos == other.pos && color == other.color && tex_coord == other.tex_coord; - } + glm::vec2 tex_coord2; static std::array get_bindings() { VkVertexInputBindingDescription binding_desc; @@ -41,7 +38,7 @@ struct Vertex { return {binding_desc}; } - static std::array get_attributes() { + static std::array get_attributes() { VkVertexInputAttributeDescription position_attrib; position_attrib.location = 0; position_attrib.binding = 0; @@ -60,7 +57,13 @@ struct Vertex { tex_coord_attrib.format = VK_FORMAT_R32G32_SFLOAT; tex_coord_attrib.offset = offsetof(struct Vertex, tex_coord); - return {position_attrib, color_attrib, tex_coord_attrib}; + VkVertexInputAttributeDescription tex_coord2_attrib; + tex_coord2_attrib.location = 3; + tex_coord2_attrib.binding = 0; + tex_coord2_attrib.format = VK_FORMAT_R32G32_SFLOAT; + tex_coord2_attrib.offset = offsetof(struct Vertex, tex_coord2); + + return {position_attrib, color_attrib, tex_coord_attrib, tex_coord2_attrib}; } }; @@ -142,8 +145,10 @@ Vulkan_Demo::Vulkan_Demo(int window_width, int window_height) create_render_pass(); create_framebuffers(); create_pipeline_layout(); - pipeline_2d = create_pipeline(false); - pipeline_3d = create_pipeline(true); + pipeline_2d = create_pipeline(false, false); + pipeline_2d_multitexture = create_pipeline(false, true); + pipeline_3d = create_pipeline(true, false); + pipeline_3d_multitexture = create_pipeline(true, true); upload_geometry(); update_ubo_descriptor(descriptor_set); @@ -293,7 +298,7 @@ void Vulkan_Demo::create_depth_buffer_resources() { } void Vulkan_Demo::create_descriptor_set_layout() { - std::array descriptor_bindings; + std::array descriptor_bindings; descriptor_bindings[0].binding = 0; descriptor_bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; descriptor_bindings[0].descriptorCount = 1; @@ -306,6 +311,12 @@ void Vulkan_Demo::create_descriptor_set_layout() { descriptor_bindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; descriptor_bindings[1].pImmutableSamplers = nullptr; + descriptor_bindings[2].binding = 2; + descriptor_bindings[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptor_bindings[2].descriptorCount = 1; + descriptor_bindings[2].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + descriptor_bindings[2].pImmutableSamplers = nullptr; + VkDescriptorSetLayoutCreateInfo desc; desc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; desc.pNext = nullptr; @@ -364,6 +375,58 @@ void Vulkan_Demo::create_image_descriptor_set(const image_t* image) { image_descriptor_sets[image] = set; } +void Vulkan_Demo::create_multitexture_descriptor_set(const image_t* image, const image_t* image2) { + VkDescriptorSetAllocateInfo desc; + desc.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + desc.pNext = nullptr; + desc.descriptorPool = descriptor_pool; + desc.descriptorSetCount = 1; + desc.pSetLayouts = &descriptor_set_layout; + + VkDescriptorSet set; + VkResult result = vkAllocateDescriptorSets(get_device(), &desc, &set); + check_vk_result(result, "vkAllocateDescriptorSets"); + + VkDescriptorImageInfo image_info[2]; + image_info[0].sampler = texture_image_sampler; + image_info[0].imageView = image->vk_image_view; + image_info[0].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + image_info[1].sampler = texture_image_sampler; + image_info[1].imageView = image2->vk_image_view; + image_info[1].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + std::array descriptor_writes; + descriptor_writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_writes[0].dstSet = set; + descriptor_writes[0].dstBinding = 1; + descriptor_writes[0].dstArrayElement = 0; + descriptor_writes[0].descriptorCount = 1; + descriptor_writes[0].pNext = nullptr; + descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptor_writes[0].pImageInfo = &image_info[0]; + descriptor_writes[0].pBufferInfo = nullptr; + descriptor_writes[0].pTexelBufferView = nullptr; + + descriptor_writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptor_writes[1].dstSet = set; + descriptor_writes[1].dstBinding = 2; + descriptor_writes[1].dstArrayElement = 0; + descriptor_writes[1].descriptorCount = 1; + descriptor_writes[1].pNext = nullptr; + descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptor_writes[1].pImageInfo = &image_info[1]; + descriptor_writes[1].pBufferInfo = nullptr; + descriptor_writes[1].pTexelBufferView = nullptr; + + vkUpdateDescriptorSets(get_device(), (uint32_t)descriptor_writes.size(), descriptor_writes.data(), 0, nullptr); + + update_ubo_descriptor(set); + + auto images = std::make_pair(image, image2); + multitexture_descriptor_sets[images] = set; +} + void Vulkan_Demo::create_render_pass() { VkAttachmentDescription color_attachment; color_attachment.flags = 0; @@ -457,9 +520,12 @@ void Vulkan_Demo::create_pipeline_layout() { pipeline_layout = get_resource_manager()->create_pipeline_layout(desc); } -VkPipeline Vulkan_Demo::create_pipeline(bool depth_test) { - Shader_Module vertex_shader("../../data/vert.spv"); - Shader_Module fragment_shader("../../data/frag.spv"); +VkPipeline Vulkan_Demo::create_pipeline(bool depth_test, bool multitexture) { + Shader_Module single_texture_vs("../../data/single_texture_vert.spv"); + Shader_Module single_texture_fs("../../data/single_texture_frag.spv"); + + Shader_Module multi_texture_vs("../../data/multi_texture_vert.spv"); + Shader_Module multi_texture_fs("../../data/multi_texture_frag.spv"); auto get_shader_stage_desc = [](VkShaderStageFlagBits stage, VkShaderModule shader_module, const char* entry) { VkPipelineShaderStageCreateInfo desc; @@ -472,9 +538,15 @@ VkPipeline Vulkan_Demo::create_pipeline(bool depth_test) { desc.pSpecializationInfo = nullptr; return desc; }; - std::vector shader_stages_state { - get_shader_stage_desc(VK_SHADER_STAGE_VERTEX_BIT, vertex_shader.handle, "main"), - get_shader_stage_desc(VK_SHADER_STAGE_FRAGMENT_BIT, fragment_shader.handle, "main") + + std::vector shader_stages_state; + + if (multitexture) { + shader_stages_state.push_back(get_shader_stage_desc(VK_SHADER_STAGE_VERTEX_BIT, multi_texture_vs.handle, "main")); + shader_stages_state.push_back(get_shader_stage_desc(VK_SHADER_STAGE_FRAGMENT_BIT, multi_texture_fs.handle, "main")); + } else { + shader_stages_state.push_back(get_shader_stage_desc(VK_SHADER_STAGE_VERTEX_BIT, single_texture_vs.handle, "main")); + shader_stages_state.push_back(get_shader_stage_desc(VK_SHADER_STAGE_FRAGMENT_BIT, single_texture_fs.handle, "main")); }; VkPipelineVertexInputStateCreateInfo vertex_input_state; @@ -879,6 +951,87 @@ void Vulkan_Demo::render_tess(const image_t* image) { tess_index_buffer_offset += tess.numIndexes * sizeof(uint32_t); } +void Vulkan_Demo::render_tess_multi(const image_t* image, const image_t* image2) { + fprintf(logfile, "render_tess_multi (vert %d, inds %d)\n", tess.numVertexes, tess.numIndexes); + fflush(logfile); + + void* data; + VkResult result = vkMapMemory(get_device(), tess_vertex_buffer_memory, tess_vertex_buffer_offset, tess.numVertexes * sizeof(Vertex), 0, &data); + check_vk_result(result, "vkMapMemory"); + Vertex* v = (Vertex*)data; + for (int i = 0; i < tess.numVertexes; i++, v++) { + v->pos.x = tess.xyz[i][0]; + v->pos.y = tess.xyz[i][1]; + v->pos.z = tess.xyz[i][2]; + v->tex_coord[0] = tess.texCoords[i][0][0]; + v->tex_coord[1] = tess.texCoords[i][0][1]; + v->tex_coord2[0] = tess.texCoords[i][1][0]; + v->tex_coord2[1] = tess.texCoords[i][1][1]; + } + vkUnmapMemory(get_device(), tess_vertex_buffer_memory); + + result = vkMapMemory(get_device(), tess_index_buffer_memory, tess_index_buffer_offset, tess.numIndexes * sizeof(uint32_t), 0, &data); + check_vk_result(result, "vkMapMemory"); + uint32_t* ind = (uint32_t*)data; + for (int i = 0; i < tess.numIndexes; i++, ind++) { + *ind = tess.indexes[i]; + } + vkUnmapMemory(get_device(), tess_index_buffer_memory); + + const VkDeviceSize offset = 0; + vkCmdBindVertexBuffers(command_buffer, 0, 1, &tess_vertex_buffer, &tess_vertex_buffer_offset); + vkCmdBindIndexBuffer(command_buffer, tess_index_buffer, tess_index_buffer_offset, VK_INDEX_TYPE_UINT32); + + auto images = std::make_pair(image, image2); + auto it = multitexture_descriptor_sets.find(images); + if (it == multitexture_descriptor_sets.cend()) { + create_multitexture_descriptor_set(image, image2); + it = multitexture_descriptor_sets.find(images); + } + auto set = it->second; + + update_uniform_buffer(); + vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout, 0, 1, &set, 1, &tess_ubo_offset); + tess_ubo_offset += tess_ubo_offset_step; + + VkViewport viewport; + VkRect2D scissor; + + if (backEnd.projection2D) { + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = (float) glConfig.vidWidth; + viewport.height = (float)glConfig.vidHeight; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + scissor.offset = {0, 0}; + scissor.extent = {(uint32_t)glConfig.vidWidth, (uint32_t)glConfig.vidHeight}; + } else { + viewport.x = backEnd.viewParms.viewportX; + viewport.y = (float)(glConfig.vidHeight - (backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight)); + viewport.width = (float) backEnd.viewParms.viewportWidth; + viewport.height = (float)backEnd.viewParms.viewportHeight; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + scissor.offset = {backEnd.viewParms.viewportX, (glConfig.vidHeight - (backEnd.viewParms.viewportY + backEnd.viewParms.viewportHeight))}; + if (scissor.offset.y < 0) scissor.offset.y = 0; // receive such data from backEnd, so just adjust to valid value to prevent vulkan warnings + scissor.extent = {(uint32_t)backEnd.viewParms.viewportWidth, (uint32_t)backEnd.viewParms.viewportHeight}; + } + + if (!backEnd.projection2D) { + vkCmdSetViewport(command_buffer, 0, 1, &viewport); + vkCmdSetScissor(command_buffer, 0, 1, &scissor); + } + + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, backEnd.projection2D ? pipeline_2d_multitexture : pipeline_3d_multitexture); + + vkCmdDrawIndexed(command_buffer, tess.numIndexes, 1, 0, 0, 0); + tess_vertex_buffer_offset += tess.numVertexes * sizeof(Vertex); + tess_index_buffer_offset += tess.numIndexes * sizeof(uint32_t); +} + void Vulkan_Demo::render_cinematic_frame() { fprintf(logfile, "render_cinematic_frame\n"); fflush(logfile); diff --git a/src/engine/renderer/vk_demo.h b/src/engine/renderer/vk_demo.h index c4c5907..159f2d8 100644 --- a/src/engine/renderer/vk_demo.h +++ b/src/engine/renderer/vk_demo.h @@ -15,6 +15,7 @@ public: void begin_frame(); void end_frame(); void render_tess(const image_t* image); + void render_tess_multi(const image_t* image, const image_t* image2); void render_cinematic_frame(); public: @@ -29,10 +30,11 @@ public: void create_descriptor_set_layout(); void create_descriptor_set(); void create_image_descriptor_set(const image_t* image); + void create_multitexture_descriptor_set(const image_t* image, const image_t* image2); void create_render_pass(); void create_framebuffers(); void create_pipeline_layout(); - VkPipeline create_pipeline(bool depth_test); + VkPipeline create_pipeline(bool depth_test, bool multitexture); void upload_geometry(); void update_ubo_descriptor(VkDescriptorSet set); @@ -62,8 +64,11 @@ public: VkRenderPass render_pass = VK_NULL_HANDLE; std::vector framebuffers; VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; + VkPipeline pipeline_2d = VK_NULL_HANDLE; + VkPipeline pipeline_2d_multitexture = VK_NULL_HANDLE; VkPipeline pipeline_3d = VK_NULL_HANDLE; + VkPipeline pipeline_3d_multitexture = VK_NULL_HANDLE; VkBuffer vertex_buffer = VK_NULL_HANDLE; VkBuffer index_buffer = VK_NULL_HANDLE; @@ -80,6 +85,7 @@ public: uint32_t tess_ubo_offset_step = -1; std::map image_descriptor_sets; // quick UI prototyping + std::map, VkDescriptorSet> multitexture_descriptor_sets; VkCommandBuffer command_buffer = VK_NULL_HANDLE;