diff --git a/util/test/demos/CMakeLists.txt b/util/test/demos/CMakeLists.txt index 89b47466b..c58e3541a 100644 --- a/util/test/demos/CMakeLists.txt +++ b/util/test/demos/CMakeLists.txt @@ -20,6 +20,7 @@ set(VULKAN_SRC vk/vk_misaligned_dirty.cpp vk/vk_multi_thread_windows.cpp vk/vk_overlay_test.cpp + vk/vk_parameter_zoo.cpp vk/vk_resource_lifetimes.cpp vk/vk_sample_locations.cpp vk/vk_secondary_cmdbuf.cpp @@ -48,6 +49,7 @@ set(OPENGL_SRC gl/gl_mip_gen_rt.cpp gl/gl_multi_window.cpp gl/gl_overlay_test.cpp + gl/gl_parameter_zoo.cpp gl/gl_per_type_tex_units.cpp gl/gl_resource_lifetimes.cpp gl/gl_runtime_bind_prog_to_pipe.cpp diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index f23674f83..337f6f904 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -184,6 +184,7 @@ + @@ -209,6 +210,7 @@ + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index 79c65916f..bf9291671 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -336,6 +336,12 @@ Vulkan\demos + + Vulkan\demos + + + OpenGL\demos + diff --git a/util/test/demos/gl/gl_parameter_zoo.cpp b/util/test/demos/gl/gl_parameter_zoo.cpp new file mode 100644 index 000000000..09e6b8c21 --- /dev/null +++ b/util/test/demos/gl/gl_parameter_zoo.cpp @@ -0,0 +1,186 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2015-2019 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "gl_test.h" + +#ifdef WIN32 +extern "C" __declspec(dllexport) GLenum APIENTRY InternalFunction() +{ + return GL_QUERY_BUFFER; +} +#endif + +TEST(GL_Parameter_Zoo, OpenGLGraphicsTest) +{ + static constexpr const char *Description = + "General tests of parameters known to cause problems - e.g. optional values that should be " + "ignored, edge cases, special values, etc."; + + const char *vertex = R"EOSHADER( +#version 450 core + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec4 Color; +layout(location = 2) in vec2 UV; + +uniform int mode; + +out vec4 v2fcol; + +void main() +{ + gl_Position = vec4(Position.xyz * (mode == 1 ? 5.0f : 1.0f), 1); + v2fcol = Color; +} + +!!!!)EOSHADER"; + + const char *pixel = R"EOSHADER( +#version 450 core + +in vec4 v2fcol; + +layout(location = 0, index = 0) out vec4 Color; +uniform int mode; + +void main() +{ + if(mode == 1) + Color = vec4(0, 0, 1, 0.5); + else + Color = v2fcol; +} + +)EOSHADER"; + + int main() + { + // initialise, create window, create context, etc + if(!Init()) + return 3; + + GLuint vao = MakeVAO(); + glBindVertexArray(vao); + + GLuint vb = MakeBuffer(); + glBindBuffer(GL_ARRAY_BUFFER, vb); + glBufferStorage(GL_ARRAY_BUFFER, sizeof(DefaultTri), DefaultTri, 0); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(DefaultA2V), (void *)(0)); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(DefaultA2V), (void *)(sizeof(Vec3f))); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(DefaultA2V), + (void *)(sizeof(Vec3f) + sizeof(Vec4f))); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + GLuint program = MakeProgram(); + + const char *nullstr = NULL; + const char *garbagestr = (const char *)0x1234; + GLint len = (int)strlen(vertex) - 5; + GLint zero = 0; + (void)len; + + GLuint vs = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vs, 1, &nullstr, &zero); + glShaderSource(vs, 1, &garbagestr, &zero); + glShaderSource(vs, 1, &vertex, &len); + glCompileShader(vs); + + GLuint fs = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fs, 1, &pixel, NULL); + glCompileShader(fs); + + glAttachShader(program, vs); + glAttachShader(program, fs); + glLinkProgram(program); + glDetachShader(program, vs); + glDetachShader(program, fs); + + glDeleteShader(vs); + glDeleteShader(fs); + + glEnable(GL_SCISSOR_TEST); + + GLuint trash = MakeBuffer(); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, trash); + glBufferStorage(GL_PIXEL_UNPACK_BUFFER, 1024, 0, 0); + glBindBuffer(GL_PIXEL_PACK_BUFFER, trash); + + if(GLAD_GL_ARB_query_buffer_object) + glBindBuffer(GL_QUERY_BUFFER, trash); + +#ifdef WIN32 + PFNGLGETERRORPROC internalFunc = + (PFNGLGETERRORPROC)GetProcAddress(GetModuleHandleA(NULL), "InternalFunction"); + + if(internalFunc == NULL || internalFunc() != GL_QUERY_BUFFER) + { + TEST_ERROR("Couldn't query own module for a function"); + program = 0; + } +#endif + + while(Running()) + { + // trash the texture pack/unpack state + glPixelStorei(GL_UNPACK_ROW_LENGTH, screenWidth + screenHeight + 99); + glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, 5); + glPixelStorei(GL_UNPACK_SKIP_PIXELS, 8180); + glPixelStorei(GL_UNPACK_SKIP_ROWS, 17); + glPixelStorei(GL_UNPACK_ALIGNMENT, 8); + + glPixelStorei(GL_PACK_ROW_LENGTH, screenWidth + screenHeight * 1 + 37); + glPixelStorei(GL_PACK_SKIP_PIXELS, 9734); + glPixelStorei(GL_PACK_SKIP_ROWS, 33); + glPixelStorei(GL_PACK_ALIGNMENT, 8); + + glViewport(0, 0, GLsizei(screenWidth), GLsizei(screenHeight)); + glScissor(0, 0, GLsizei(screenWidth), GLsizei(screenHeight)); + + float col[] = {0.4f, 0.5f, 0.6f, 1.0f}; + glClearBufferfv(GL_COLOR, 0, col); + + glBindVertexArray(vao); + + glUseProgram(program); + + glProgramUniform1i(program, glGetUniformLocation(program, "mode"), 0); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glScissor(320, 50, 1, 1); + + glProgramUniform1i(program, glGetUniformLocation(program, "mode"), 1); + glDrawArrays(GL_TRIANGLES, 0, 3); + + Present(); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/demos/vk/vk_parameter_zoo.cpp b/util/test/demos/vk/vk_parameter_zoo.cpp new file mode 100644 index 000000000..c42f890ed --- /dev/null +++ b/util/test/demos/vk/vk_parameter_zoo.cpp @@ -0,0 +1,452 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "vk_test.h" + +TEST(VK_Parameter_Zoo, VulkanGraphicsTest) +{ + static constexpr const char *Description = + "General tests of parameters known to cause problems - e.g. optional values that should be " + "ignored, edge cases, special values, etc."; + + std::string common = R"EOSHADER( + +#version 420 core + +struct v2f +{ + vec4 pos; + vec4 col; + vec4 uv; +}; + +)EOSHADER"; + + const std::string vertex = R"EOSHADER( + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec4 Color; +layout(location = 2) in vec2 UV; + +layout(location = 0) out v2f vertOut; + +void main() +{ + vertOut.pos = vec4(Position.xyz*vec3(1,-1,1), 1); + gl_Position = vertOut.pos; + vertOut.col = Color; + vertOut.uv = vec4(UV.xy, 0, 1); +} + +)EOSHADER"; + + const std::string pixel = R"EOSHADER( + +layout(location = 0) in v2f vertIn; + +layout(location = 0, index = 0) out vec4 Color; + +void main() +{ + Color = vertIn.col; +} + +)EOSHADER"; + + int main() + { + optDevExts.push_back(VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME); + optDevExts.push_back(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME); + + // initialise, create window, create context, etc + if(!Init()) + return 3; + + bool KHR_descriptor_update_template = + std::find(devExts.begin(), devExts.end(), + VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME) != devExts.end(); + bool KHR_push_descriptor = std::find(devExts.begin(), devExts.end(), + VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME) != devExts.end(); + + VkDescriptorSetLayout setlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({ + {0, VK_DESCRIPTOR_TYPE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {4, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {5, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {6, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {8, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {9, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {10, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, VK_SHADER_STAGE_VERTEX_BIT}, + })); + + VkDescriptorSetLayout pushlayout = VK_NULL_HANDLE; + VkPipelineLayout layout; + + if(KHR_push_descriptor) + { + pushlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo( + { + {5, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {10, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT}, + {20, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT}, + }, + VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR)); + + layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo({setlayout, pushlayout})); + } + else + { + layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo({setlayout})); + } + + vkh::GraphicsPipelineCreateInfo pipeCreateInfo; + + pipeCreateInfo.layout = layout; + pipeCreateInfo.renderPass = mainWindow->rp; + + pipeCreateInfo.vertexInputState.vertexBindingDescriptions = {vkh::vertexBind(0, DefaultA2V)}; + pipeCreateInfo.vertexInputState.vertexAttributeDescriptions = { + vkh::vertexAttr(0, 0, DefaultA2V, pos), vkh::vertexAttr(1, 0, DefaultA2V, col), + vkh::vertexAttr(2, 0, DefaultA2V, uv), + }; + + pipeCreateInfo.stages = { + CompileShaderModule(common + vertex, ShaderLang::glsl, ShaderStage::vert, "main"), + CompileShaderModule(common + pixel, ShaderLang::glsl, ShaderStage::frag, "main"), + }; + + VkPipeline pipe; + + // invalid handle - should not be used because the flag for derived pipelines is not used + pipeCreateInfo.basePipelineHandle = (VkPipeline)0x1234; + + CHECK_VKR(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, pipeCreateInfo, NULL, &pipe)); + vkDestroyPipeline(device, pipe, NULL); + + pipeCreateInfo.basePipelineHandle = VK_NULL_HANDLE; + pipeCreateInfo.basePipelineIndex = 3; + + CHECK_VKR(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, pipeCreateInfo, NULL, &pipe)); + vkDestroyPipeline(device, pipe, NULL); + + pipe = createGraphicsPipeline(pipeCreateInfo); + + AllocatedBuffer vb( + allocator, vkh::BufferCreateInfo(sizeof(DefaultTri), VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); + + vb.upload(DefaultTri); + + VkDescriptorSet descset = allocateDescriptorSet(setlayout); + + VkSampler invalidSampler = (VkSampler)0x1234; + VkSampler validSampler = VK_NULL_HANDLE; + VkSamplerCreateInfo sampInfo = {VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO}; + sampInfo.magFilter = VK_FILTER_LINEAR; + sampInfo.minFilter = VK_FILTER_LINEAR; + vkCreateSampler(device, &sampInfo, NULL, &validSampler); + + AllocatedBuffer buf(allocator, + vkh::BufferCreateInfo(1024, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | + VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_CPU_TO_GPU})); + + VkBuffer invalidBuffer = (VkBuffer)0x1234; + VkBuffer validBuffer = buf.buffer; + + AllocatedImage img(allocator, + vkh::ImageCreateInfo(4, 4, 0, VK_FORMAT_R32G32B32A32_SFLOAT, + VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); + + VkImage validImage = img.image; + + VkImageView validImgView = createImageView( + vkh::ImageViewCreateInfo(validImage, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32G32B32A32_SFLOAT)); + VkImageView invalidImgView = (VkImageView)0x1234; + + { + VkCommandBuffer cmd = GetCommandBuffer(); + vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); + vkh::cmdPipelineBarrier(cmd, { + vkh::ImageMemoryBarrier(0, 0, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_GENERAL, img.image), + }); + vkEndCommandBuffer(cmd); + Submit(99, 99, {cmd}); + } + + VkBufferView validBufView = + createBufferView(vkh::BufferViewCreateInfo(validBuffer, VK_FORMAT_R32G32B32A32_SFLOAT)); + VkBufferView invalidBufView = (VkBufferView)0x1234; + + // initialise the writes with the valid data + std::vector validBufInfos = {vkh::DescriptorBufferInfo(validBuffer)}; + std::vector validBufViews = {validBufView}; + std::vector validSoloImgs = { + vkh::DescriptorImageInfo(validImgView, VK_IMAGE_LAYOUT_GENERAL), + }; + std::vector validCombinedImgs = { + vkh::DescriptorImageInfo(validImgView, VK_IMAGE_LAYOUT_GENERAL, validSampler), + }; + std::vector validSamplers = { + vkh::DescriptorImageInfo(VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED, validSampler), + }; + + std::vector writes = { + vkh::WriteDescriptorSet(descset, 0, VK_DESCRIPTOR_TYPE_SAMPLER, validSamplers), + vkh::WriteDescriptorSet(descset, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, + validCombinedImgs), + vkh::WriteDescriptorSet(descset, 2, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, validSoloImgs), + vkh::WriteDescriptorSet(descset, 3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, validSoloImgs), + + vkh::WriteDescriptorSet(descset, 4, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, validBufViews), + vkh::WriteDescriptorSet(descset, 5, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, validBufViews), + + vkh::WriteDescriptorSet(descset, 6, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, validBufInfos), + vkh::WriteDescriptorSet(descset, 7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, validBufInfos), + vkh::WriteDescriptorSet(descset, 8, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, validBufInfos), + vkh::WriteDescriptorSet(descset, 9, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, validBufInfos), + }; + + // do a first update + vkh::updateDescriptorSets(device, writes); + + // set invalid handles but valid pointers and try again + VkDescriptorBufferInfo invalidBufInfo = {}; + invalidBufInfo.buffer = invalidBuffer; + + VkDescriptorImageInfo invalidImgInfo = {}; + invalidImgInfo.sampler = invalidSampler; + invalidImgInfo.imageView = invalidImgView; + + validSoloImgs[0].sampler = invalidSampler; + validSamplers[0].imageView = invalidImgView; + + writes[0].pTexelBufferView = &invalidBufView; + writes[0].pBufferInfo = &invalidBufInfo; + + writes[1].pTexelBufferView = &invalidBufView; + writes[1].pBufferInfo = &invalidBufInfo; + + writes[2].pTexelBufferView = &invalidBufView; + writes[2].pBufferInfo = &invalidBufInfo; + + writes[3].pTexelBufferView = &invalidBufView; + writes[3].pBufferInfo = &invalidBufInfo; + + writes[4].pImageInfo = &invalidImgInfo; + writes[4].pBufferInfo = &invalidBufInfo; + + writes[5].pImageInfo = &invalidImgInfo; + writes[5].pBufferInfo = &invalidBufInfo; + + writes[6].pTexelBufferView = &invalidBufView; + writes[6].pImageInfo = &invalidImgInfo; + + writes[7].pTexelBufferView = &invalidBufView; + writes[7].pImageInfo = &invalidImgInfo; + + writes[8].pTexelBufferView = &invalidBufView; + writes[8].pImageInfo = &invalidImgInfo; + + writes[9].pTexelBufferView = &invalidBufView; + writes[9].pImageInfo = &invalidImgInfo; + + vkh::updateDescriptorSets(device, writes); + + // finally set invalid pointers too + VkBufferView *invalidBufViews = (VkBufferView *)0x1234; + vkh::DescriptorBufferInfo *invalidBufInfos = (vkh::DescriptorBufferInfo *)0x1234; + vkh::DescriptorImageInfo *invalidImgInfos = (vkh::DescriptorImageInfo *)0x1234; + + writes[0].pTexelBufferView = invalidBufViews; + writes[0].pBufferInfo = invalidBufInfos; + + writes[1].pTexelBufferView = invalidBufViews; + writes[1].pBufferInfo = invalidBufInfos; + + writes[2].pTexelBufferView = invalidBufViews; + writes[2].pBufferInfo = invalidBufInfos; + + writes[3].pTexelBufferView = invalidBufViews; + writes[3].pBufferInfo = invalidBufInfos; + + writes[4].pImageInfo = invalidImgInfos; + writes[4].pBufferInfo = invalidBufInfos; + + writes[5].pImageInfo = invalidImgInfos; + writes[5].pBufferInfo = invalidBufInfos; + + writes[6].pTexelBufferView = invalidBufViews; + writes[6].pImageInfo = invalidImgInfos; + + writes[7].pTexelBufferView = invalidBufViews; + writes[7].pImageInfo = invalidImgInfos; + + writes[8].pTexelBufferView = invalidBufViews; + writes[8].pImageInfo = invalidImgInfos; + + writes[9].pTexelBufferView = invalidBufViews; + writes[9].pImageInfo = invalidImgInfos; + + vkh::updateDescriptorSets(device, writes); + + if(KHR_descriptor_update_template) + { + struct datastruct + { + VkBufferView view; + VkDescriptorBufferInfo buf; + VkDescriptorImageInfo img; + VkDescriptorImageInfo combined; + VkDescriptorImageInfo sampler; + } data; + + data.view = validBufView; + data.buf = validBufInfos[0]; + data.img = vkh::DescriptorImageInfo(validImgView, VK_IMAGE_LAYOUT_GENERAL); + data.combined = vkh::DescriptorImageInfo(validImgView, VK_IMAGE_LAYOUT_GENERAL, validSampler); + data.sampler = + vkh::DescriptorImageInfo(VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED, validSampler); + data.img.sampler = invalidSampler; + data.sampler.imageView = invalidImgView; + + std::vector entries = { + // descriptor count 0 updates are allowed + {0, 0, 0, VK_DESCRIPTOR_TYPE_SAMPLER, 0, sizeof(data)}, + {0, 0, 1, VK_DESCRIPTOR_TYPE_SAMPLER, offsetof(datastruct, sampler), sizeof(data)}, + {1, 0, 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, offsetof(datastruct, combined), + sizeof(data)}, + {2, 0, 1, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, offsetof(datastruct, img), sizeof(data)}, + {3, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, offsetof(datastruct, img), sizeof(data)}, + {4, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, offsetof(datastruct, view), sizeof(data)}, + {5, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, offsetof(datastruct, view), sizeof(data)}, + {6, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, offsetof(datastruct, buf), sizeof(data)}, + {7, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, offsetof(datastruct, buf), sizeof(data)}, + {8, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, offsetof(datastruct, buf), + sizeof(data)}, + {9, 0, 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, offsetof(datastruct, buf), + sizeof(data)}, + }; + + VkDescriptorUpdateTemplateCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR; + createInfo.descriptorUpdateEntryCount = (uint32_t)entries.size(); + createInfo.pDescriptorUpdateEntries = entries.data(); + createInfo.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR; + createInfo.descriptorSetLayout = setlayout; + createInfo.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + createInfo.pipelineLayout = layout; + createInfo.set = 0; + VkDescriptorUpdateTemplateKHR templ; + vkCreateDescriptorUpdateTemplateKHR(device, &createInfo, NULL, &templ); + + vkUpdateDescriptorSetWithTemplateKHR(device, descset, templ, &data); + + vkDestroyDescriptorUpdateTemplateKHR(device, templ, NULL); + } + + struct pushdatastruct + { + VkDescriptorBufferInfo buf; + } pushdata; + + pushdata.buf = validBufInfos[0]; + + VkDescriptorUpdateTemplateKHR pushtempl = VK_NULL_HANDLE; + if(KHR_descriptor_update_template && KHR_push_descriptor) + { + std::vector entries = { + {0, 0, 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, sizeof(pushdata)}, + {10, 0, 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, sizeof(pushdata)}, + }; + + VkDescriptorUpdateTemplateCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR; + createInfo.descriptorUpdateEntryCount = (uint32_t)entries.size(); + createInfo.pDescriptorUpdateEntries = entries.data(); + createInfo.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR; + createInfo.descriptorSetLayout = pushlayout; + createInfo.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + createInfo.pipelineLayout = layout; + createInfo.set = 1; + vkCreateDescriptorUpdateTemplateKHR(device, &createInfo, NULL, &pushtempl); + } + + while(Running()) + { + VkCommandBuffer cmd = GetCommandBuffer(); + + vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); + + VkImage swapimg = + StartUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + + vkCmdClearColorImage(cmd, swapimg, VK_IMAGE_LAYOUT_GENERAL, + vkh::ClearColorValue(0.4f, 0.5f, 0.6f, 1.0f), 1, + vkh::ImageSubresourceRange()); + + vkCmdBeginRenderPass( + cmd, vkh::RenderPassBeginInfo(mainWindow->rp, mainWindow->GetFB(), mainWindow->scissor), + VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); + vkCmdSetViewport(cmd, 0, 1, &mainWindow->viewport); + vkCmdSetScissor(cmd, 0, 1, &mainWindow->scissor); + vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {0}); + vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, {descset}, {0, 0}); + vkCmdPushDescriptorSetKHR( + cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 1, 1, + vkh::WriteDescriptorSet(VK_NULL_HANDLE, 20, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + validBufInfos)); + if(KHR_descriptor_update_template && KHR_push_descriptor) + vkCmdPushDescriptorSetWithTemplateKHR(cmd, pushtempl, layout, 1, &pushdata); + vkCmdDraw(cmd, 3, 1, 0, 0); + + vkCmdEndRenderPass(cmd); + + FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL); + + vkEndCommandBuffer(cmd); + + Submit(0, 1, {cmd}); + + Present(); + } + + if(KHR_descriptor_update_template && KHR_push_descriptor) + vkDestroyDescriptorUpdateTemplateKHR(device, pushtempl, NULL); + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/rdtest/util.py b/util/test/rdtest/util.py index e467bd25b..5be9c535d 100644 --- a/util/test/rdtest/util.py +++ b/util/test/rdtest/util.py @@ -141,6 +141,15 @@ def sanitise_filename(name: str): return re.sub('^/', '', name) +def linear_to_SRGB(val): + if type(val) == float: + if val <= 0.0031308: + return val * 12.92 + else: + return 1.055 * math.pow(val, 1.0 / 2.4) - 0.055 + + return [linear_to_SRGB(v) for v in val] + def png_save(out_path: str, rows: List[bytes], dimensions: Tuple[int, int], has_alpha: bool): try: f = open(out_path, 'wb') diff --git a/util/test/tests/GL/GL_Parameter_Zoo.py b/util/test/tests/GL/GL_Parameter_Zoo.py new file mode 100644 index 000000000..ebc264aea --- /dev/null +++ b/util/test/tests/GL/GL_Parameter_Zoo.py @@ -0,0 +1,106 @@ +import struct +import math +import renderdoc as rd +import rdtest + + +class GL_Parameter_Zoo(rdtest.TestCase): + demos_test_name = 'GL_Parameter_Zoo' + + def check_capture(self): + id = self.get_last_draw().copyDestination + + tex_details = self.get_texture(id) + + self.controller.SetFrameEvent(self.get_last_draw().eventId, True) + + data = self.controller.GetTextureData(id, 0, 0) + first_pixel = struct.unpack_from("BBBB", data, 0) + + val = [int(round(v * 255)) for v in rdtest.linear_to_SRGB([0.4, 0.5, 0.6, 1.0])] + if not rdtest.value_compare(first_pixel, val): + raise rdtest.TestFailureException("First pixel should be clear color {}, not {}".format(val, first_pixel)) + + magic_pixel = struct.unpack_from("BBBB", data, (50 * tex_details.width + 320) * 4) + + if not rdtest.value_compare(magic_pixel, [0, 0, 255, 127]): + raise rdtest.TestFailureException("Pixel @ 320,50 should be blue: {}, not {}".format(val, magic_pixel)) + + rdtest.log.success("Decoded pixels from texture data are correct") + + img_path = rdtest.get_tmp_path('preserved_alpha.png') + + self.controller.SetFrameEvent(self.get_last_draw().eventId, True) + + save_data = rd.TextureSave() + save_data.resourceId = id + save_data.destType = rd.FileType.PNG + save_data.alpha = rd.AlphaMapping.Discard # this should not discard the alpha + + self.controller.SaveTexture(save_data, img_path) + + data = rdtest.png_load_data(img_path) + + magic_pixel = struct.unpack_from("BBBB", data[-1-50], 320 * 4) + + if not rdtest.value_compare(magic_pixel, [0, 0, 255, 127]): + raise rdtest.TestFailureException("Pixel @ 320,50 should be blue: {}, not {}".format(val, magic_pixel)) + + draw = self.find_draw("Draw") + + self.controller.SetFrameEvent(draw.eventId, False) + + postvs_data = self.get_postvs(rd.MeshDataStage.VSOut, 0, draw.numIndices) + + postvs_ref = { + 0: { + 'vtx': 0, + 'idx': 0, + 'gl_Position': [-0.5, -0.5, 0.0, 1.0], + 'v2fcol': [1.0, 0.0, 0.0, 1.0], + }, + 1: { + 'vtx': 1, + 'idx': 1, + 'gl_Position': [0.0, 0.5, 0.0, 1.0], + 'v2fcol': [0.0, 1.0, 0.0, 1.0], + }, + 2: { + 'vtx': 2, + 'idx': 2, + 'gl_Position': [0.5, -0.5, 0.0, 1.0], + 'v2fcol': [0.0, 0.0, 1.0, 1.0], + }, + } + + self.check_mesh_data(postvs_ref, postvs_data) + + results = self.controller.FetchCounters([rd.GPUCounter.RasterizedPrimitives, rd.GPUCounter.VSInvocations, rd.GPUCounter.FSInvocations]) + + results = [r for r in results if r.eventId == draw.eventId] + + if len(results) != 3: + raise rdtest.TestFailureException("Expected 3 results, got {} results".format(len(results))) + + for r in results: + r: rd.CounterResult + val = r.value.u32 + if r.counter == rd.GPUCounter.RasterizedPrimitives: + if not rdtest.value_compare(val, 1): + raise rdtest.TestFailureException("RasterizedPrimitives result {} is not as expected".format(val)) + else: + rdtest.log.success("RasterizedPrimitives result is as expected") + elif r.counter == rd.GPUCounter.VSInvocations: + if not rdtest.value_compare(val, 3): + raise rdtest.TestFailureException("VSInvocations result {} is not as expected".format(val)) + else: + rdtest.log.success("VSInvocations result is as expected") + elif r.counter == rd.GPUCounter.FSInvocations: + if val < int(0.1 * tex_details.width * tex_details.height): + raise rdtest.TestFailureException("FSInvocations result {} is not as expected".format(val)) + else: + rdtest.log.success("FSInvocations result is as expected") + else: + raise rdtest.TestFailureException("Unexpected counter result {}".format(r.counter)) + + rdtest.log.success("Counter data retrieved successfully") diff --git a/util/test/tests/Vulkan/VK_Parameter_Zoo.py b/util/test/tests/Vulkan/VK_Parameter_Zoo.py new file mode 100644 index 000000000..7d9faffd1 --- /dev/null +++ b/util/test/tests/Vulkan/VK_Parameter_Zoo.py @@ -0,0 +1,42 @@ +import renderdoc as rd +import rdtest + + +class VK_Parameter_Zoo(rdtest.TestCase): + demos_test_name = 'VK_Parameter_Zoo' + + def check_capture(self): + draw = self.find_draw("Draw") + + self.controller.SetFrameEvent(draw.eventId, False) + + postvs_data = self.get_postvs(rd.MeshDataStage.VSOut, 0, draw.numIndices) + + postvs_ref = { + 0: { + 'vtx': 0, + 'idx': 0, + 'gl_PerVertex.gl_Position': [-0.5, 0.5, 0.0, 1.0], + 'vertOut.pos': [-0.5, 0.5, 0.0, 1.0], + 'vertOut.col': [1.0, 0.0, 0.0, 1.0], + 'vertOut.uv': [0.0, 0.0, 0.0, 1.0], + }, + 1: { + 'vtx': 1, + 'idx': 1, + 'gl_PerVertex.gl_Position': [0.0, -0.5, 0.0, 1.0], + 'vertOut.pos': [0.0, -0.5, 0.0, 1.0], + 'vertOut.col': [0.0, 1.0, 0.0, 1.0], + 'vertOut.uv': [0.0, 1.0, 0.0, 1.0], + }, + 2: { + 'vtx': 2, + 'idx': 2, + 'gl_PerVertex.gl_Position': [0.5, 0.5, 0.0, 1.0], + 'vertOut.pos': [0.5, 0.5, 0.0, 1.0], + 'vertOut.col': [0.0, 0.0, 1.0, 1.0], + 'vertOut.uv': [1.0, 0.0, 0.0, 1.0], + }, + } + + self.check_mesh_data(postvs_ref, postvs_data)