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 0000000..d6370f0 Binary files /dev/null and b/data/multi_texture_frag.spv differ diff --git a/data/multi_texture_vert.spv b/data/multi_texture_vert.spv new file mode 100644 index 0000000..d005787 Binary files /dev/null and b/data/multi_texture_vert.spv differ 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;