From 34fbfb4352d65a1fb609afba356aac03af1786a3 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 3 Nov 2026 16:24:58 +0000 Subject: [PATCH] Add D3D11/Vk demos that do rasterization with no outputs * They write directly to a buffer --- .../test/demos/d3d11/d3d11_storage_raster.cpp | 123 +++++++++++ util/test/demos/demos.vcxproj | 2 + util/test/demos/demos.vcxproj.filters | 6 + util/test/demos/vk/vk_storage_raster.cpp | 191 ++++++++++++++++++ 4 files changed, 322 insertions(+) create mode 100644 util/test/demos/d3d11/d3d11_storage_raster.cpp create mode 100644 util/test/demos/vk/vk_storage_raster.cpp diff --git a/util/test/demos/d3d11/d3d11_storage_raster.cpp b/util/test/demos/d3d11/d3d11_storage_raster.cpp new file mode 100644 index 000000000..50876770e --- /dev/null +++ b/util/test/demos/d3d11/d3d11_storage_raster.cpp @@ -0,0 +1,123 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2023-2026 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 "d3d11_test.h" + +RD_TEST(D3D11_Storage_Raster, D3D11GraphicsTest) +{ + static constexpr const char *Description = + "Testing stores to images from a rasterized draw with no rasterized outputs."; + + std::string vertex = R"EOSHADER( + +struct vertin +{ + float3 pos : POSITION; + float4 col : COLOR0; + float2 uv : TEXCOORD0; +}; + +struct v2f +{ + float4 pos : SV_POSITION; + float4 col : COLOR0; + float2 uv : TEXCOORD0; +}; + +v2f main(vertin IN) +{ + v2f OUT = (v2f)0; + + OUT.pos = float4(IN.pos.xyz, 1); + OUT.col = IN.col; + OUT.uv = IN.uv; + + return OUT; +} + +)EOSHADER"; + + std::string pixel = R"EOSHADER( + +struct v2f +{ + float4 pos : SV_POSITION; + float4 col : COLOR0; + float2 uv : TEXCOORD0; +}; + +RWByteAddressBuffer rwbuf : register(u0); + +void main(v2f IN) +{ + uint orig = 0; + rwbuf.InterlockedMin(0, uint(IN.pos.x), orig); + rwbuf.InterlockedMin(4, uint(IN.pos.y), orig); + rwbuf.InterlockedMax(8, uint(IN.pos.x), orig); + rwbuf.InterlockedMax(12, uint(IN.pos.y), orig); +} + +)EOSHADER"; + + int main() + { + // initialise, create window, create device, etc + if(!Init()) + return 3; + + ID3D11VertexShaderPtr vs = CreateVS(Compile(vertex, "main", "vs_5_0")); + ID3D11PixelShaderPtr ps = CreatePS(Compile(pixel, "main", "ps_5_0")); + + ID3D11BufferPtr buf = MakeBuffer().Size(64).ByteAddressed().UAV().SRV(); + ID3D11UnorderedAccessViewPtr uav = MakeUAV(buf).Format(DXGI_FORMAT_R32_TYPELESS); + + while(Running()) + { + ClearRenderTargetView(bbRTV, {0.2f, 0.2f, 0.2f, 1.0f}); + + ClearUnorderedAccessView(uav, Vec4u(150, 150, 150, 150)); + + IASetVertexBuffer(DefaultTriVB, sizeof(DefaultA2V), 0); + ctx->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + ctx->IASetInputLayout(defaultLayout); + + ctx->VSSetShader(vs, NULL, 0); + ctx->PSSetShader(ps, NULL, 0); + + RSSetViewport({0.0f, 0.0f, (float)screenWidth, (float)screenHeight, 0.0f, 1.0f}); + RSSetScissor({0, 0, screenWidth, screenHeight}); + + ctx->OMSetRenderTargetsAndUnorderedAccessViews(0, NULL, NULL, 0, 1, &uav.GetInterfacePtr(), + NULL); + + ctx->Draw(3, 0); + + Present(); + } + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index 9d3870ecb..d438e02c8 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -158,6 +158,7 @@ + @@ -349,6 +350,7 @@ + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index 0f76c0aa3..9bf5192ab 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -775,6 +775,12 @@ Vulkan\demos + + Vulkan\demos + + + D3D11\demos + diff --git a/util/test/demos/vk/vk_storage_raster.cpp b/util/test/demos/vk/vk_storage_raster.cpp new file mode 100644 index 000000000..19bace0c2 --- /dev/null +++ b/util/test/demos/vk/vk_storage_raster.cpp @@ -0,0 +1,191 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2023-2026 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" + +RD_TEST(VK_Storage_Raster, VulkanGraphicsTest) +{ + static constexpr const char *Description = + "Testing stores to images from a rasterized draw with no rasterized outputs."; + + std::string common = R"EOSHADER( + +#version 450 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(set = 0, binding = 0, std430) buffer atomicbuftype +{ + uint data[]; +} atomicbuf; + +void main() +{ + atomicMin(atomicbuf.data[0], int(gl_FragCoord.x)); + atomicMin(atomicbuf.data[1], int(gl_FragCoord.y)); + atomicMax(atomicbuf.data[2], int(gl_FragCoord.x)); + atomicMax(atomicbuf.data[3], int(gl_FragCoord.y)); +} + +)EOSHADER"; + + void Prepare(int argc, char **argv) + { + features.fragmentStoresAndAtomics = VK_TRUE; + + VulkanGraphicsTest::Prepare(argc, argv); + + if(!Avail.empty()) + return; + } + + int main() + { + // initialise, create window, create context, etc + if(!Init()) + return 3; + + AllocatedBuffer store_buffer(this, + vkh::BufferCreateInfo(64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT), + VmaAllocationCreateInfo({0, VMA_MEMORY_USAGE_GPU_ONLY})); + + VkRenderPass noAttRP; + + vkh::RenderPassCreator renderPassCreateInfo; + renderPassCreateInfo.addSubpass({}); + noAttRP = createRenderPass(renderPassCreateInfo); + + VkExtent2D fbRect = {(uint32_t)screenWidth, (uint32_t)screenHeight}; + + VkFramebuffer noAttFB = createFramebuffer(vkh::FramebufferCreateInfo(noAttRP, {}, fbRect)); + + vkh::GraphicsPipelineCreateInfo pipeCreateInfo; + + VkDescriptorSetLayout setlayout = createDescriptorSetLayout(vkh::DescriptorSetLayoutCreateInfo({ + {0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, + })); + + VkPipelineLayout layout = createPipelineLayout(vkh::PipelineLayoutCreateInfo({setlayout})); + + pipeCreateInfo.layout = layout; + pipeCreateInfo.renderPass = noAttRP; + + pipeCreateInfo.multisampleState.rasterizationSamples = VK_SAMPLE_COUNT_4_BIT; + + 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 = createGraphicsPipeline(pipeCreateInfo); + + VkDescriptorSet descset = allocateDescriptorSet(setlayout); + + vkh::updateDescriptorSets( + device, { + vkh::WriteDescriptorSet(descset, 0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, + {vkh::DescriptorBufferInfo(store_buffer.buffer)}), + }); + + while(Running()) + { + VkCommandBuffer cmd = GetCommandBuffer(); + + vkBeginCommandBuffer(cmd, vkh::CommandBufferBeginInfo()); + + vkCmdFillBuffer(cmd, store_buffer.buffer, 0, 64, 150); + + vkh::cmdPipelineBarrier( + cmd, {}, + {vkh::BufferMemoryBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, + VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, + store_buffer.buffer)}); + + VkImage swapimg = StartUsingBackbuffer(cmd); + + vkCmdClearColorImage(cmd, swapimg, VK_IMAGE_LAYOUT_GENERAL, + vkh::ClearColorValue(0.2f, 0.2f, 0.2f, 1.0f), 1, + vkh::ImageSubresourceRange()); + + vkCmdBeginRenderPass(cmd, vkh::RenderPassBeginInfo(noAttRP, noAttFB, mainWindow->scissor), + VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipe); + mainWindow->setViewScissor(cmd); + vkh::cmdBindVertexBuffers(cmd, {DefaultTriVB.buffer}); + vkh::cmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, {descset}, {}); + vkCmdDraw(cmd, 3, 1, 0, 0); + + vkCmdEndRenderPass(cmd); + + FinishUsingBackbuffer(cmd); + + vkEndCommandBuffer(cmd); + + SubmitAndPresent({cmd}); + } + + return 0; + } +}; + +REGISTER_TEST();