Add test cases of shader editing on GL and Vulkan

This commit is contained in:
baldurk
2019-09-05 18:56:16 +01:00
parent 852e538145
commit c9f13a657d
8 changed files with 857 additions and 6 deletions
+2
View File
@@ -23,6 +23,7 @@ set(VULKAN_SRC
vk/vk_resource_lifetimes.cpp
vk/vk_sample_locations.cpp
vk/vk_secondary_cmdbuf.cpp
vk/vk_shader_editing.cpp
vk/vk_simple_triangle.cpp
vk/vk_spec_constants.cpp
vk/vk_spirv_13_shaders.cpp
@@ -51,6 +52,7 @@ set(OPENGL_SRC
gl/gl_resource_lifetimes.cpp
gl/gl_runtime_bind_prog_to_pipe.cpp
gl/gl_separable_geometry_shader.cpp
gl/gl_shader_editing.cpp
gl/gl_simple_triangle.cpp
gl/gl_spirv_shader.cpp
gl/gl_unsized_ms_fbo_attachment.cpp
+2
View File
@@ -188,6 +188,7 @@
<ClCompile Include="gl\gl_resource_lifetimes.cpp" />
<ClCompile Include="gl\gl_runtime_bind_prog_to_pipe.cpp" />
<ClCompile Include="gl\gl_separable_geometry_shader.cpp" />
<ClCompile Include="gl\gl_shader_editing.cpp" />
<ClCompile Include="gl\gl_simple_triangle.cpp" />
<ClCompile Include="gl\gl_spirv_shader.cpp" />
<ClCompile Include="gl\gl_structured_buffer_nested.cpp" />
@@ -214,6 +215,7 @@
<ClCompile Include="vk\vk_line_raster.cpp" />
<ClCompile Include="vk\vk_misaligned_dirty.cpp" />
<ClCompile Include="vk\vk_multi_thread_windows.cpp" />
<ClCompile Include="vk\vk_shader_editing.cpp" />
<ClCompile Include="vk\vk_spec_constants.cpp" />
<ClCompile Include="vk\vk_spirv_13_shaders.cpp" />
<ClCompile Include="vk\vk_triangle_fan.cpp" />
+6
View File
@@ -330,6 +330,12 @@
<ClCompile Include="vk\vk_misaligned_dirty.cpp">
<Filter>Vulkan\demos</Filter>
</ClCompile>
<ClCompile Include="gl\gl_shader_editing.cpp">
<Filter>OpenGL\demos</Filter>
</ClCompile>
<ClCompile Include="vk\vk_shader_editing.cpp">
<Filter>Vulkan\demos</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Filter Include="D3D11">
+238
View File
@@ -0,0 +1,238 @@
/******************************************************************************
* 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"
TEST(GL_Shader_Editing, OpenGLGraphicsTest)
{
static constexpr const char *Description =
"Ensures that shader editing works with different combinations of shader re-use and handles "
"locations that change between the pre-edit and post-edit shaders.";
const char *vertex = R"EOSHADER(
#version 430 core
layout(location = 0) in vec3 Position;
layout(location = 1) in vec4 Color;
layout(location = 2) in vec2 UV;
#define v2f v2f_block \
{ \
vec4 pos; \
vec4 col; \
vec4 uv; \
}
out v2f vertOut;
out gl_PerVertex { vec4 gl_Position; };
void main()
{
vertOut.pos = vec4(Position.xyz, 1);
gl_Position = vertOut.pos;
vertOut.col = Color;
vertOut.uv = vec4(UV.xy, 0, 1);
}
)EOSHADER";
const char *pixel = R"EOSHADER(
#version 430 core
layout(location = 0, index = 0) out vec4 Color;
layout(location = 9) uniform vec4 col;
void main()
{
Color = col.rgba;
}
)EOSHADER";
const char *pixel2 = R"EOSHADER(
#version 430 core
layout(location = 0, index = 0) out vec4 Color;
// we hope that having these uniforms be first both alphabetically, by use, and by declaration, that
// they'll be assigned earlier locations.
// Then when we remove the declration and use it should force zcol to get a lower location value
// after the edit.
#if 1
uniform vec4 acol;
uniform vec4 bcol;
uniform vec4 ccol;
#endif
uniform vec4 zcol;
void main()
{
#if 1
Color = acol + bcol + ccol;
#endif
Color += zcol.rgba;
}
)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 fixedprog = MakeProgram();
GLuint dynamicprog = MakeProgram();
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vertex, NULL);
glCompileShader(vs);
GLuint fs1 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs1, 1, &pixel, NULL);
glCompileShader(fs1);
GLuint fs2 = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs2, 1, &pixel2, NULL);
glCompileShader(fs2);
glAttachShader(fixedprog, vs);
glAttachShader(fixedprog, fs1);
glLinkProgram(fixedprog);
glDetachShader(fixedprog, vs);
glDetachShader(fixedprog, fs1);
glAttachShader(dynamicprog, vs);
glAttachShader(dynamicprog, fs2);
glLinkProgram(dynamicprog);
glDetachShader(dynamicprog, vs);
glDetachShader(dynamicprog, fs2);
glDeleteShader(vs);
glDeleteShader(fs1);
glDeleteShader(fs2);
GLuint pipe = MakePipeline();
GLuint vssepprog = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &vertex);
GLuint fssepprog = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &pixel);
glUseProgramStages(pipe, GL_VERTEX_SHADER_BIT, vssepprog);
glUseProgramStages(pipe, GL_FRAGMENT_SHADER_BIT, fssepprog);
glProgramUniform4f(fssepprog, 9, 0.0f, 1.0f, 0.0f, 1.0f);
// render offscreen to make picked values accurate
GLuint fbo = MakeFBO();
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
// Color render texture
GLuint colattach = MakeTexture();
glBindTexture(GL_TEXTURE_2D, colattach);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, screenWidth, screenHeight);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colattach, 0);
GLuint zcol = glGetUniformLocation(dynamicprog, "zcol");
while(Running())
{
float col[] = {0.4f, 0.5f, 0.6f, 1.0f};
glClearBufferfv(GL_COLOR, 0, col);
glBindVertexArray(vao);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glUseProgram(fixedprog);
GLsizei hw = GLsizei(screenWidth) / 2;
GLsizei hh = GLsizei(screenHeight) / 2;
glViewport(0, hh, hw, hh);
glUniform4f(9, 0.0f, 1.0f, 0.0f, 1.0f);
glUniform4f(10, 1.0f, 0.0f, 0.0f, 1.0f);
glDrawArrays(GL_TRIANGLES, 0, 3);
glViewport(hw, hh, hw, hh);
glUniform4f(9, 0.0f, 0.5f, 0.0f, 1.0f);
glUniform4f(10, 0.5f, 0.0f, 0.0f, 1.0f);
setMarker("fixedprog");
glDrawArrays(GL_TRIANGLES, 0, 3);
glViewport(0, 0, hw, hh);
glUseProgram(dynamicprog);
glUniform4f(zcol, 0.0f, 1.0f, 0.0f, 1.0f);
setMarker("dynamicprog");
glDrawArrays(GL_TRIANGLES, 0, 3);
glViewport(hw, 0, hw, hh);
// finally draw with the separable pipeline to ensure we can edit that
glBindProgramPipeline(pipe);
glUseProgram(0);
setMarker("sepprog");
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindProgramPipeline(0);
// give us a point to select where all uniforms are trashed
glUseProgram(fixedprog);
glUniform4f(9, 0.0f, 0.0f, 0.0f, 1.0f);
glUniform4f(10, 0.0f, 0.0f, 0.0f, 1.0f);
glUseProgram(dynamicprog);
glUniform4f(zcol, 0.0f, 0.0f, 0.0f, 1.0f);
glBlitNamedFramebuffer(fbo, 0, 0, 0, screenWidth, screenHeight, 0, 0, screenWidth,
screenHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
Present();
}
return 0;
}
};
REGISTER_TEST();
+25 -6
View File
@@ -504,7 +504,8 @@ float4 main() : SV_Target0
AllocatedImage img(
allocator,
vkh::ImageCreateInfo(mainWindow->scissor.extent.width, mainWindow->scissor.extent.height, 0,
VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT),
VK_FORMAT_R32G32B32A32_SFLOAT,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT),
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY}));
VkImageView imgview = createImageView(
@@ -600,12 +601,8 @@ float4 main() : SV_Target0
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(renderPass, framebuffer, mainWindow->scissor,
{vkh::ClearValue(0.0f, 0.0f, 0.0f, 1.0f)}),
{vkh::ClearValue(0.4f, 0.5f, 0.6f, 1.0f)}),
VK_SUBPASS_CONTENTS_INLINE);
vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, {descset}, {});
@@ -621,6 +618,28 @@ float4 main() : SV_Target0
vkCmdEndRenderPass(cmd);
vkh::cmdPipelineBarrier(
cmd, {
vkh::ImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_GENERAL, img.image),
});
VkImageBlit region = {};
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.srcSubresource.layerCount = 1;
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.dstSubresource.layerCount = 1;
region.srcOffsets[1].x = mainWindow->scissor.extent.width;
region.srcOffsets[1].y = mainWindow->scissor.extent.height;
region.srcOffsets[1].z = 1;
region.dstOffsets[1].x = mainWindow->scissor.extent.width;
region.dstOffsets[1].y = mainWindow->scissor.extent.height;
region.dstOffsets[1].z = 1;
vkCmdBlitImage(cmd, img.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL, 1,
&region, VK_FILTER_LINEAR);
FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
vkEndCommandBuffer(cmd);
+189
View File
@@ -0,0 +1,189 @@
/******************************************************************************
* 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_Shader_Editing, VulkanGraphicsTest)
{
static constexpr const char *Description =
"Ensures that shader editing works with different combinations of shader re-use.";
const char *vertex = R"EOSHADER(
#version 430 core
layout(location = 0) in vec3 Position;
void main()
{
gl_Position = vec4(Position.xyz, 1);
}
)EOSHADER";
const char *pixel = R"EOSHADER(
#version 430 core
layout(location = 0, index = 0) out vec4 Color;
void main()
{
#if 1
Color = vec4(0.0, 1.0, 0.0, 1.0);
#else
Color = vec4(0.0, 1.0, 1.0, 1.0);
#endif
}
)EOSHADER";
int main()
{
// initialise, create window, create context, etc
if(!Init())
return 3;
VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo());
AllocatedImage img(
allocator,
vkh::ImageCreateInfo(mainWindow->scissor.extent.width, mainWindow->scissor.extent.height, 0,
VK_FORMAT_R32G32B32A32_SFLOAT,
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT),
VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY}));
VkImageView imgview = createImageView(
vkh::ImageViewCreateInfo(img.image, VK_IMAGE_VIEW_TYPE_2D, VK_FORMAT_R32G32B32A32_SFLOAT));
vkh::RenderPassCreator renderPassCreateInfo;
renderPassCreateInfo.attachments.push_back(
vkh::AttachmentDescription(VK_FORMAT_R32G32B32A32_SFLOAT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL, VK_ATTACHMENT_LOAD_OP_CLEAR));
renderPassCreateInfo.addSubpass({VkAttachmentReference({0, VK_IMAGE_LAYOUT_GENERAL})});
VkRenderPass renderPass = createRenderPass(renderPassCreateInfo);
VkFramebuffer framebuffer = createFramebuffer(
vkh::FramebufferCreateInfo(renderPass, {imgview}, mainWindow->scissor.extent));
vkh::GraphicsPipelineCreateInfo pipeCreateInfo;
pipeCreateInfo.layout = layout;
pipeCreateInfo.renderPass = renderPass;
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(vertex, ShaderLang::glsl, ShaderStage::vert, "main"),
CompileShaderModule(pixel, ShaderLang::glsl, ShaderStage::frag, "main"),
};
VkPipeline pipe = createGraphicsPipeline(pipeCreateInfo);
// use the same source but make a distinct shader module so we can edit it separately
pipeCreateInfo.stages[1] =
CompileShaderModule(pixel, ShaderLang::glsl, ShaderStage::frag, "main");
VkPipeline pipe2 = 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);
while(Running())
{
VkCommandBuffer cmd = GetCommandBuffer();
vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo());
VkImage swapimg =
StartUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(renderPass, framebuffer, mainWindow->scissor,
{vkh::ClearValue(0.4f, 0.5f, 0.6f, 1.0f)}),
VK_SUBPASS_CONTENTS_INLINE);
VkViewport v = mainWindow->viewport;
v.width /= 2.0f;
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe);
vkCmdSetViewport(cmd, 0, 1, &v);
vkCmdSetScissor(cmd, 0, 1, &mainWindow->scissor);
vkh::cmdBindVertexBuffers(cmd, 0, {vb.buffer}, {0});
setMarker(cmd, "Draw 1");
vkCmdDraw(cmd, 3, 1, 0, 0);
v.x += v.width;
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2);
vkCmdSetViewport(cmd, 0, 1, &v);
setMarker(cmd, "Draw 2");
vkCmdDraw(cmd, 3, 1, 0, 0);
vkCmdEndRenderPass(cmd);
vkh::cmdPipelineBarrier(
cmd, {
vkh::ImageMemoryBarrier(VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_GENERAL, img.image),
});
VkImageBlit region = {};
region.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.srcSubresource.layerCount = 1;
region.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.dstSubresource.layerCount = 1;
region.srcOffsets[1].x = mainWindow->scissor.extent.width;
region.srcOffsets[1].y = mainWindow->scissor.extent.height;
region.srcOffsets[1].z = 1;
region.dstOffsets[1].x = mainWindow->scissor.extent.width;
region.dstOffsets[1].y = mainWindow->scissor.extent.height;
region.dstOffsets[1].z = 1;
vkCmdBlitImage(cmd, img.image, VK_IMAGE_LAYOUT_GENERAL, swapimg, VK_IMAGE_LAYOUT_GENERAL, 1,
&region, VK_FILTER_LINEAR);
FinishUsingBackbuffer(cmd, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_LAYOUT_GENERAL);
vkEndCommandBuffer(cmd);
Submit(0, 1, {cmd});
Present();
}
return 0;
}
};
REGISTER_TEST();
+236
View File
@@ -0,0 +1,236 @@
import copy
import rdtest
import renderdoc as rd
from typing import Tuple
class GL_Shader_Editing(rdtest.TestCase):
demos_test_name = 'GL_Shader_Editing'
def check_capture(self):
eid = self.find_draw("fixedprog").eventId
self.controller.SetFrameEvent(eid, False)
pipe: rd.PipeState = self.controller.GetPipelineState()
fixedrefl: rd.ShaderReflection = pipe.GetShaderReflection(rd.ShaderStage.Fragment)
eid = self.find_draw("dynamicprog").eventId
self.controller.SetFrameEvent(eid, False)
pipe: rd.PipeState = self.controller.GetPipelineState()
dynamicrefl: rd.ShaderReflection = pipe.GetShaderReflection(rd.ShaderStage.Fragment)
vsrefl: rd.ShaderReflection = pipe.GetShaderReflection(rd.ShaderStage.Vertex)
eid = self.find_draw("sepprog").eventId
self.controller.SetFrameEvent(eid, False)
vsseprefl: rd.ShaderReflection = pipe.GetShaderReflection(rd.ShaderStage.Vertex)
fsseprefl: rd.ShaderReflection = pipe.GetShaderReflection(rd.ShaderStage.Fragment)
# Work at the last draw, where the uniforms have been trashed
self.controller.SetFrameEvent(self.get_last_draw().eventId, False)
tex: rd.ResourceId = pipe.GetOutputTargets()[0].resourceId
# On upper row: Left triangle is fully green, right triangle is half-green
# On lower row: Left triangle is fully green
self.check_pixel_value(tex, 0.25, 0.25, [0.0, 1.0, 0.0, 1.0])
self.check_pixel_value(tex, 0.75, 0.25, [0.0, 0.5, 0.0, 1.0])
self.check_pixel_value(tex, 0.25, 0.75, [0.0, 1.0, 0.0, 1.0])
rdtest.log.success("Values are as expected initially")
source: bytes = fixedrefl.rawBytes.replace(b'.rgba', b'.rgga').replace(b'location = 9', b'location = 10')
newShader: Tuple[rd.ResourceId, str] = self.controller.BuildTargetShader(fixedrefl.entryPoint,
fixedrefl.encoding, source,
rd.ShaderCompileFlags(),
rd.ShaderStage.Fragment)
if len(newShader[1]) != 0:
raise rdtest.TestFailureException("Failed to compile edited shader: {}".format(newShader[1]))
fixedFS = newShader[0]
source: bytes = dynamicrefl.rawBytes.replace(b'.rgba', b'.rgga').replace(b'#if 1', b'#if 0')
newShader: Tuple[rd.ResourceId, str] = self.controller.BuildTargetShader(dynamicrefl.entryPoint,
dynamicrefl.encoding, source,
rd.ShaderCompileFlags(),
rd.ShaderStage.Fragment)
if len(newShader[1]) != 0:
raise rdtest.TestFailureException("Failed to compile edited shader: {}".format(newShader[1]))
dynamicFS = newShader[0]
source: bytes = vsrefl.rawBytes.replace(b'Position.xyz', b'Position.xyz+vec3(1.0)')
newShader: Tuple[rd.ResourceId, str] = self.controller.BuildTargetShader(vsrefl.entryPoint,
vsrefl.encoding, source,
rd.ShaderCompileFlags(),
rd.ShaderStage.Vertex)
if len(newShader[1]) != 0:
raise rdtest.TestFailureException("Failed to compile edited shader: {}".format(newShader[1]))
offsetVS = newShader[0]
source: bytes = vsrefl.rawBytes
newShader: Tuple[rd.ResourceId, str] = self.controller.BuildTargetShader(vsrefl.entryPoint,
vsrefl.encoding, source,
rd.ShaderCompileFlags(),
rd.ShaderStage.Vertex)
if len(newShader[1]) != 0:
raise rdtest.TestFailureException("Failed to compile edited shader: {}".format(newShader[1]))
nochangeVS = newShader[0]
source: bytes = vsseprefl.rawBytes.replace(b'Position.xyz', b'Position.xyz+vec3(1.0)')
newShader: Tuple[rd.ResourceId, str] = self.controller.BuildTargetShader(vsseprefl.entryPoint,
vsseprefl.encoding, source,
rd.ShaderCompileFlags(),
rd.ShaderStage.Vertex)
if len(newShader[1]) != 0:
raise rdtest.TestFailureException("Failed to compile edited shader: {}".format(newShader[1]))
sepVS = newShader[0]
source: bytes = fsseprefl.rawBytes.replace(b'.rgba', b'.rgga')
newShader: Tuple[rd.ResourceId, str] = self.controller.BuildTargetShader(fsseprefl.entryPoint,
fsseprefl.encoding, source,
rd.ShaderCompileFlags(),
rd.ShaderStage.Fragment)
if len(newShader[1]) != 0:
raise rdtest.TestFailureException("Failed to compile edited shader: {}".format(newShader[1]))
sepFS = newShader[0]
# Edit both fragment shaders
self.controller.ReplaceResource(fixedrefl.resourceId, fixedFS)
self.controller.ReplaceResource(dynamicrefl.resourceId, dynamicFS)
# Refresh the replay if it didn't happen already
self.controller.SetFrameEvent(self.get_last_draw().eventId, True)
# Triangles have green propagated across to the blue channel
self.check_pixel_value(tex, 0.25, 0.25, [0.0, 1.0, 1.0, 1.0])
self.check_pixel_value(tex, 0.75, 0.25, [0.0, 0.5, 0.5, 1.0])
self.check_pixel_value(tex, 0.25, 0.75, [0.0, 1.0, 1.0, 1.0])
rdtest.log.success("Values are as expected after fragment editing")
# Now "edit" the VS but don't change it. We should still get the same values
self.controller.ReplaceResource(vsrefl.resourceId, nochangeVS)
self.controller.SetFrameEvent(self.get_last_draw().eventId, True)
# Triangles have green propagated across to the blue channel
self.check_pixel_value(tex, 0.25, 0.25, [0.0, 1.0, 1.0, 1.0])
self.check_pixel_value(tex, 0.75, 0.25, [0.0, 0.5, 0.5, 1.0])
self.check_pixel_value(tex, 0.25, 0.75, [0.0, 1.0, 1.0, 1.0])
rdtest.log.success("Values are as expected after no-op vertex editing")
# Change the VS to one that has offset the triangles off-centre
self.controller.ReplaceResource(vsrefl.resourceId, offsetVS)
self.controller.SetFrameEvent(self.get_last_draw().eventId, True)
# Original sample positions are now the clear color
self.check_pixel_value(tex, 0.25, 0.25, [0.4, 0.5, 0.6, 1.0])
self.check_pixel_value(tex, 0.75, 0.25, [0.4, 0.5, 0.6, 1.0])
self.check_pixel_value(tex, 0.25, 0.75, [0.4, 0.5, 0.6, 1.0])
# The triangles are still the same colour but up and to the right
self.check_pixel_value(tex, 0.45, 0.05, [0.0, 1.0, 1.0, 1.0])
self.check_pixel_value(tex, 0.95, 0.05, [0.0, 0.5, 0.5, 1.0])
self.check_pixel_value(tex, 0.45, 0.55, [0.0, 1.0, 1.0, 1.0])
rdtest.log.success("Values are as expected after offset vertex editing")
# Now undo the first FS edit
self.controller.RemoveReplacement(fixedrefl.resourceId)
self.controller.SetFrameEvent(self.get_last_draw().eventId, True)
# Original sample positions are still the clear color
self.check_pixel_value(tex, 0.25, 0.25, [0.4, 0.5, 0.6, 1.0])
self.check_pixel_value(tex, 0.75, 0.25, [0.4, 0.5, 0.6, 1.0])
self.check_pixel_value(tex, 0.25, 0.75, [0.4, 0.5, 0.6, 1.0])
# The lower triangle is the edited colour, the other two have reverted to green channel only
self.check_pixel_value(tex, 0.45, 0.05, [0.0, 1.0, 0.0, 1.0])
self.check_pixel_value(tex, 0.95, 0.05, [0.0, 0.5, 0.0, 1.0])
self.check_pixel_value(tex, 0.45, 0.55, [0.0, 1.0, 1.0, 1.0])
rdtest.log.success("Values are as expected after removing first fragment edit")
# Now undo the first VS edit
self.controller.RemoveReplacement(vsrefl.resourceId)
self.controller.SetFrameEvent(self.get_last_draw().eventId, True)
# Only the lower triangle is the edited colour, but they are back in the original positions
self.check_pixel_value(tex, 0.25, 0.25, [0.0, 1.0, 0.0, 1.0])
self.check_pixel_value(tex, 0.75, 0.25, [0.0, 0.5, 0.0, 1.0])
self.check_pixel_value(tex, 0.25, 0.75, [0.0, 1.0, 1.0, 1.0])
rdtest.log.success("Values are as expected after removing vertex edit")
# finally undo the second FS edit
self.controller.RemoveReplacement(dynamicrefl.resourceId)
self.controller.SetFrameEvent(self.get_last_draw().eventId, True)
# We should be back to where we started
self.check_pixel_value(tex, 0.25, 0.25, [0.0, 1.0, 0.0, 1.0])
self.check_pixel_value(tex, 0.75, 0.25, [0.0, 0.5, 0.0, 1.0])
self.check_pixel_value(tex, 0.25, 0.75, [0.0, 1.0, 0.0, 1.0])
rdtest.log.success("Values are as expected after removing all edits")
rdtest.log.success("Linked program editing succeeded")
# Check that we can edit separable shaders
# Only looking at bottom left triangle, it should be green
self.check_pixel_value(tex, 0.75, 0.75, [0.0, 1.0, 0.0, 1.0])
self.controller.ReplaceResource(fsseprefl.resourceId, sepFS)
self.controller.SetFrameEvent(self.get_last_draw().eventId, True)
# Now it should be green-blue
self.check_pixel_value(tex, 0.75, 0.75, [0.0, 1.0, 1.0, 1.0])
self.controller.ReplaceResource(vsseprefl.resourceId, sepVS)
self.controller.SetFrameEvent(self.get_last_draw().eventId, True)
# Now it should be green-blue and offset
self.check_pixel_value(tex, 0.75, 0.75, [0.4, 0.5, 0.6, 1.0])
self.check_pixel_value(tex, 0.95, 0.55, [0.0, 1.0, 1.0, 1.0])
self.controller.RemoveReplacement(fsseprefl.resourceId)
self.controller.SetFrameEvent(self.get_last_draw().eventId, True)
# Now it should be back to green and offset
self.check_pixel_value(tex, 0.75, 0.75, [0.4, 0.5, 0.6, 1.0])
self.check_pixel_value(tex, 0.95, 0.55, [0.0, 1.0, 0.0, 1.0])
self.controller.RemoveReplacement(vsseprefl.resourceId)
self.controller.SetFrameEvent(self.get_last_draw().eventId, True)
# We should be back to where we started
self.check_pixel_value(tex, 0.75, 0.75, [0.0, 1.0, 0.0, 1.0])
rdtest.log.success("Separable program editing succeeded")
self.controller.FreeTargetResource(nochangeVS)
self.controller.FreeTargetResource(offsetVS)
self.controller.FreeTargetResource(fixedFS)
self.controller.FreeTargetResource(dynamicFS)
self.controller.FreeTargetResource(sepVS)
self.controller.FreeTargetResource(sepFS)
+159
View File
@@ -0,0 +1,159 @@
import copy
import rdtest
import renderdoc as rd
from typing import Tuple
class VK_Shader_Editing(rdtest.TestCase):
demos_test_name = 'VK_Shader_Editing'
def check_capture(self):
eid = self.find_draw("Draw 1").next.eventId
self.controller.SetFrameEvent(eid, False)
pipe: rd.PipeState = self.controller.GetPipelineState()
fsrefl1: rd.ShaderReflection = pipe.GetShaderReflection(rd.ShaderStage.Fragment)
eid = self.find_draw("Draw 2").next.eventId
self.controller.SetFrameEvent(eid, False)
pipe: rd.PipeState = self.controller.GetPipelineState()
fsrefl2: rd.ShaderReflection = pipe.GetShaderReflection(rd.ShaderStage.Fragment)
vsrefl: rd.ShaderReflection = pipe.GetShaderReflection(rd.ShaderStage.Vertex)
tex: rd.ResourceId = pipe.GetOutputTargets()[0].resourceId
# Both triangles should be green
self.check_pixel_value(tex, 0.25, 0.5, [0.0, 1.0, 0.0, 1.0])
self.check_pixel_value(tex, 0.75, 0.5, [0.0, 1.0, 0.0, 1.0])
rdtest.log.success("Values are as expected initially")
source: str = fsrefl1.debugInfo.files[0].contents.replace('#if 1', '#if 0')
newShader: Tuple[rd.ResourceId, str] = self.controller.BuildTargetShader(fsrefl1.entryPoint,
rd.ShaderEncoding.GLSL,
bytes(source, 'UTF-8'),
rd.ShaderCompileFlags(),
rd.ShaderStage.Fragment)
if len(newShader[1]) != 0:
raise rdtest.TestFailureException("Failed to compile edited shader: {}".format(newShader[1]))
FS1 = newShader[0]
source: str = fsrefl2.debugInfo.files[0].contents.replace('#if 1', '#if 0')
newShader: Tuple[rd.ResourceId, str] = self.controller.BuildTargetShader(fsrefl2.entryPoint,
rd.ShaderEncoding.GLSL,
bytes(source, 'UTF-8'),
rd.ShaderCompileFlags(),
rd.ShaderStage.Fragment)
if len(newShader[1]) != 0:
raise rdtest.TestFailureException("Failed to compile edited shader: {}".format(newShader[1]))
FS2 = newShader[0]
source: str = vsrefl.debugInfo.files[0].contents.replace('Position.xyz', 'Position.xyz+vec3(1.0)')
newShader: Tuple[rd.ResourceId, str] = self.controller.BuildTargetShader(vsrefl.entryPoint,
rd.ShaderEncoding.GLSL,
bytes(source, 'UTF-8'),
rd.ShaderCompileFlags(),
rd.ShaderStage.Vertex)
if len(newShader[1]) != 0:
raise rdtest.TestFailureException("Failed to compile edited shader: {}".format(newShader[1]))
offsetVS = newShader[0]
source: bytes = vsrefl.rawBytes
newShader: Tuple[rd.ResourceId, str] = self.controller.BuildTargetShader(vsrefl.entryPoint,
vsrefl.encoding, source,
rd.ShaderCompileFlags(),
rd.ShaderStage.Vertex)
if len(newShader[1]) != 0:
raise rdtest.TestFailureException("Failed to compile edited shader: {}".format(newShader[1]))
nochangeVS = newShader[0]
# Edit both fragment shaders
self.controller.ReplaceResource(fsrefl1.resourceId, FS1)
self.controller.ReplaceResource(fsrefl2.resourceId, FS2)
# Refresh the replay if it didn't happen already
self.controller.SetFrameEvent(eid, True)
# Triangles have green and blue channel
self.check_pixel_value(tex, 0.25, 0.5, [0.0, 1.0, 1.0, 1.0])
self.check_pixel_value(tex, 0.75, 0.5, [0.0, 1.0, 1.0, 1.0])
rdtest.log.success("Values are as expected after fragment editing")
# Now "edit" the VS but don't change it. We should still get the same values
self.controller.ReplaceResource(vsrefl.resourceId, nochangeVS)
self.controller.SetFrameEvent(eid, True)
# Triangles have green and blue channel
self.check_pixel_value(tex, 0.25, 0.5, [0.0, 1.0, 1.0, 1.0])
self.check_pixel_value(tex, 0.75, 0.5, [0.0, 1.0, 1.0, 1.0])
rdtest.log.success("Values are as expected after no-op vertex editing")
# Change the VS to one that has offset the triangles off-centre
self.controller.ReplaceResource(vsrefl.resourceId, offsetVS)
self.controller.SetFrameEvent(eid, True)
# Original sample positions are now the clear color
self.check_pixel_value(tex, 0.25, 0.5, [0.4, 0.5, 0.6, 1.0])
self.check_pixel_value(tex, 0.75, 0.5, [0.4, 0.5, 0.6, 1.0])
# Triangles have green and blue channel
self.check_pixel_value(tex, 0.45, 0.95, [0.0, 1.0, 1.0, 1.0])
self.check_pixel_value(tex, 0.95, 0.95, [0.0, 1.0, 1.0, 1.0])
rdtest.log.success("Values are as expected after offset vertex editing")
# Now undo the first FS edit
self.controller.RemoveReplacement(fsrefl1.resourceId)
self.controller.SetFrameEvent(eid, True)
# Original sample positions are still the clear color
self.check_pixel_value(tex, 0.25, 0.5, [0.4, 0.5, 0.6, 1.0])
self.check_pixel_value(tex, 0.75, 0.5, [0.4, 0.5, 0.6, 1.0])
# The right triangle is the edited colour, the other two have reverted to green channel only
self.check_pixel_value(tex, 0.45, 0.95, [0.0, 1.0, 0.0, 1.0])
self.check_pixel_value(tex, 0.95, 0.95, [0.0, 1.0, 1.0, 1.0])
rdtest.log.success("Values are as expected after removing first fragment edit")
# Now undo the first VS edit
self.controller.RemoveReplacement(vsrefl.resourceId)
self.controller.SetFrameEvent(eid, True)
# The right triangle is the edited colour, but they are back in the original positions
self.check_pixel_value(tex, 0.25, 0.5, [0.0, 1.0, 0.0, 1.0])
self.check_pixel_value(tex, 0.75, 0.5, [0.0, 1.0, 1.0, 1.0])
rdtest.log.success("Values are as expected after removing vertex edit")
# finally undo the second FS edit
self.controller.RemoveReplacement(fsrefl2.resourceId)
self.controller.SetFrameEvent(eid, True)
# We should be back to where we started
self.check_pixel_value(tex, 0.25, 0.5, [0.0, 1.0, 0.0, 1.0])
self.check_pixel_value(tex, 0.75, 0.5, [0.0, 1.0, 0.0, 1.0])
rdtest.log.success("Values are as expected after removing all edits")
self.controller.FreeTargetResource(nochangeVS)
self.controller.FreeTargetResource(offsetVS)
self.controller.FreeTargetResource(FS1)
self.controller.FreeTargetResource(FS2)