Change render passes from multi to single pass.
This as an API change to get closer to the direction in which WebGPU is headed. The API change in next.json caused a ton of files to be changed in the same commit to keep things compiling. API: the Framebuffer and RenderPass objects are now merged in a single RenderPassInfo that contains the attachments, loadOps and clear values for a BeginRenderPass command. The concept of subpass is removed. The RenderPass creation argument to RenderPipelines is replaced by explicitly setting the format of attachments for RenderPipeline. Validation: SetPipeline checks are changed to check that the attachments info set on a RenderPipeline matches the attachments of the render pass. Backends: Most changes are simplifications of the backends that no longer require and indirection to query the current subpass out of the render pass in BeginSubpass, and don't need to get the attachment info from a RenderPass when creating RenderPipelines. In the Vulkan backend, a VkRenderPass cache is added to reuse VkRenderPasses between RenderPassInfos and RenderPipelines. Tests and examples: they are updated with the simplified API. Tests specific to the Framebuffer and RenderPass objects were removed and validation tests for RenderPassInfo were added. Tested by running CppHelloTriangle on all backends, end2end tests on all platforms and all examples on the GL backend.
This commit is contained in:
parent
87ec361cc2
commit
6f7749cce9
|
@ -26,7 +26,6 @@ nxt::Queue queue;
|
|||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
|
||||
float RandomFloat(float min, float max) {
|
||||
float zeroOne = rand() / float(RAND_MAX);
|
||||
|
@ -108,11 +107,11 @@ void init() {
|
|||
fragColor = v_color;
|
||||
})");
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.GetResult();
|
||||
|
@ -130,8 +129,8 @@ void init() {
|
|||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
nxt::RenderPassInfo renderPass;
|
||||
GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
|
||||
|
||||
static int f = 0;
|
||||
f++;
|
||||
|
@ -141,8 +140,7 @@ void frame() {
|
|||
nxt::CommandBuffer commands;
|
||||
{
|
||||
nxt::CommandBufferBuilder builder = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.Clone();
|
||||
|
||||
|
@ -153,7 +151,6 @@ void frame() {
|
|||
i++;
|
||||
}
|
||||
|
||||
builder.EndRenderSubpass();
|
||||
builder.EndRenderPass();
|
||||
commands = builder.GetResult();
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ nxtDevice device;
|
|||
nxtQueue queue;
|
||||
nxtSwapChain swapchain;
|
||||
nxtRenderPipeline pipeline;
|
||||
nxtRenderPass renderpass;
|
||||
|
||||
nxtTextureFormat swapChainFormat;
|
||||
|
||||
|
@ -61,18 +60,9 @@ void init() {
|
|||
"}\n";
|
||||
nxtShaderModule fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, fs).Release();
|
||||
|
||||
{
|
||||
nxtRenderPassBuilder builder = nxtDeviceCreateRenderPassBuilder(device);
|
||||
nxtRenderPassBuilderSetAttachmentCount(builder, 1);
|
||||
nxtRenderPassBuilderAttachmentSetFormat(builder, 0, swapChainFormat);
|
||||
nxtRenderPassBuilderSetSubpassCount(builder, 1);
|
||||
nxtRenderPassBuilderSubpassSetColorAttachment(builder, 0, 0, 0);
|
||||
renderpass = nxtRenderPassBuilderGetResult(builder);
|
||||
nxtRenderPassBuilderRelease(builder);
|
||||
}
|
||||
{
|
||||
nxtRenderPipelineBuilder builder = nxtDeviceCreateRenderPipelineBuilder(device);
|
||||
nxtRenderPipelineBuilderSetSubpass(builder, renderpass, 0);
|
||||
nxtRenderPipelineBuilderSetColorAttachmentFormat(builder, 0, swapChainFormat);
|
||||
nxtRenderPipelineBuilderSetStage(builder, NXT_SHADER_STAGE_VERTEX, vsModule, "main");
|
||||
nxtRenderPipelineBuilderSetStage(builder, NXT_SHADER_STAGE_FRAGMENT, fsModule, "main");
|
||||
pipeline = nxtRenderPipelineBuilderGetResult(builder);
|
||||
|
@ -91,23 +81,19 @@ void frame() {
|
|||
backbufferView = nxtTextureViewBuilderGetResult(builder);
|
||||
nxtTextureViewBuilderRelease(builder);
|
||||
}
|
||||
nxtFramebuffer framebuffer;
|
||||
nxtRenderPassInfo renderpassInfo;
|
||||
{
|
||||
nxtFramebufferBuilder builder = nxtDeviceCreateFramebufferBuilder(device);
|
||||
nxtFramebufferBuilderSetRenderPass(builder, renderpass);
|
||||
nxtFramebufferBuilderSetDimensions(builder, 640, 480);
|
||||
nxtFramebufferBuilderSetAttachment(builder, 0, backbufferView);
|
||||
framebuffer = nxtFramebufferBuilderGetResult(builder);
|
||||
nxtFramebufferBuilderRelease(builder);
|
||||
nxtRenderPassInfoBuilder builder = nxtDeviceCreateRenderPassInfoBuilder(device);
|
||||
nxtRenderPassInfoBuilderSetColorAttachment(builder, 0, backbufferView, NXT_LOAD_OP_CLEAR);
|
||||
renderpassInfo = nxtRenderPassInfoBuilderGetResult(builder);
|
||||
nxtRenderPassInfoBuilderRelease(builder);
|
||||
}
|
||||
nxtCommandBuffer commands;
|
||||
{
|
||||
nxtCommandBufferBuilder builder = nxtDeviceCreateCommandBufferBuilder(device);
|
||||
nxtCommandBufferBuilderBeginRenderPass(builder, renderpass, framebuffer);
|
||||
nxtCommandBufferBuilderBeginRenderSubpass(builder);
|
||||
nxtCommandBufferBuilderBeginRenderPass(builder, renderpassInfo);
|
||||
nxtCommandBufferBuilderSetRenderPipeline(builder, pipeline);
|
||||
nxtCommandBufferBuilderDrawArrays(builder, 3, 1, 0, 0);
|
||||
nxtCommandBufferBuilderEndRenderSubpass(builder);
|
||||
nxtCommandBufferBuilderEndRenderPass(builder);
|
||||
commands = nxtCommandBufferBuilderGetResult(builder);
|
||||
nxtCommandBufferBuilderRelease(builder);
|
||||
|
@ -117,7 +103,7 @@ void frame() {
|
|||
nxtCommandBufferRelease(commands);
|
||||
nxtTextureTransitionUsage(backbuffer, NXT_TEXTURE_USAGE_BIT_PRESENT);
|
||||
nxtSwapChainPresent(swapchain, backbuffer);
|
||||
nxtFramebufferRelease(framebuffer);
|
||||
nxtRenderPassInfoRelease(renderpassInfo);
|
||||
nxtTextureViewRelease(backbufferView);
|
||||
|
||||
DoFlush();
|
||||
|
|
|
@ -32,7 +32,6 @@ nxt::Buffer modelBuffer;
|
|||
std::array<nxt::Buffer, 2> particleBuffers;
|
||||
|
||||
nxt::RenderPipeline renderPipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
|
||||
nxt::Buffer updateParams;
|
||||
nxt::ComputePipeline updatePipeline;
|
||||
|
@ -123,11 +122,11 @@ void initRender() {
|
|||
.SetInput(1, sizeof(glm::vec2), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
renderPipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
|
@ -260,7 +259,7 @@ void initSim() {
|
|||
}
|
||||
}
|
||||
|
||||
nxt::CommandBuffer createCommandBuffer(const nxt::Framebuffer& framebuffer, size_t i) {
|
||||
nxt::CommandBuffer createCommandBuffer(const nxt::RenderPassInfo& renderPass, size_t i) {
|
||||
static const uint32_t zeroOffsets[1] = {0};
|
||||
auto& bufferSrc = particleBuffers[i];
|
||||
auto& bufferDst = particleBuffers[(i + 1) % 2];
|
||||
|
@ -273,14 +272,12 @@ nxt::CommandBuffer createCommandBuffer(const nxt::Framebuffer& framebuffer, size
|
|||
.Dispatch(kNumParticles, 1, 1)
|
||||
.EndComputePass()
|
||||
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass)
|
||||
.SetRenderPipeline(renderPipeline)
|
||||
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Vertex)
|
||||
.SetVertexBuffers(0, 1, &bufferDst, zeroOffsets)
|
||||
.SetVertexBuffers(1, 1, &modelBuffer, zeroOffsets)
|
||||
.DrawArrays(3, kNumParticles, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
|
||||
.GetResult();
|
||||
|
@ -301,10 +298,10 @@ void init() {
|
|||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
nxt::RenderPassInfo renderPass;
|
||||
GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
|
||||
|
||||
nxt::CommandBuffer commandBuffer = createCommandBuffer(framebuffer, pingpong);
|
||||
nxt::CommandBuffer commandBuffer = createCommandBuffer(renderPass, pingpong);
|
||||
queue.Submit(1, &commandBuffer);
|
||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||
swapchain.Present(backbuffer);
|
||||
|
|
|
@ -26,7 +26,6 @@ nxt::TextureView depthStencilView;
|
|||
nxt::Buffer buffer;
|
||||
nxt::RenderPipeline renderPipeline;
|
||||
nxt::BindGroup renderBindGroup;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::ComputePipeline computePipeline;
|
||||
nxt::BindGroup computeBindGroup;
|
||||
|
||||
|
@ -113,11 +112,11 @@ void init() {
|
|||
.SetBindGroupLayout(0, bgl)
|
||||
.GetResult();
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
renderPipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -133,8 +132,8 @@ void init() {
|
|||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
nxt::RenderPassInfo renderPass;
|
||||
GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.TransitionBufferUsage(buffer, nxt::BufferUsageBit::Storage)
|
||||
|
@ -145,12 +144,10 @@ void frame() {
|
|||
.EndComputePass()
|
||||
|
||||
.TransitionBufferUsage(buffer, nxt::BufferUsageBit::Uniform)
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass)
|
||||
.SetRenderPipeline(renderPipeline)
|
||||
.SetBindGroup(0, renderBindGroup)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
|
||||
.GetResult();
|
||||
|
|
|
@ -40,7 +40,6 @@ nxt::TextureView depthStencilView;
|
|||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPipeline planePipeline;
|
||||
nxt::RenderPipeline reflectionPipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
|
||||
void initBuffers() {
|
||||
static const uint32_t indexData[6*6] = {
|
||||
|
@ -209,7 +208,6 @@ void init() {
|
|||
.SetBufferViews(1, 1, &transformBufferView[1])
|
||||
.GetResult();
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
auto depthStencilState = device.CreateDepthStencilStateBuilder()
|
||||
|
@ -218,7 +216,8 @@ void init() {
|
|||
.GetResult();
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -234,7 +233,8 @@ void init() {
|
|||
.GetResult();
|
||||
|
||||
planePipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -249,7 +249,8 @@ void init() {
|
|||
.GetResult();
|
||||
|
||||
reflectionPipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsReflectionModule, "main")
|
||||
|
@ -277,12 +278,11 @@ void frame() {
|
|||
cameraBuffer.SetSubData(0, sizeof(CameraData), reinterpret_cast<uint8_t*>(&cameraData));
|
||||
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
nxt::RenderPassInfo renderPass;
|
||||
GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.TransitionBufferUsage(cameraBuffer, nxt::BufferUsageBit::Uniform)
|
||||
.SetBindGroup(0, bindGroup[0])
|
||||
|
@ -300,7 +300,6 @@ void frame() {
|
|||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.SetBindGroup(0, bindGroup[1])
|
||||
.DrawElements(36, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ nxt::Queue queue;
|
|||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
|
||||
void initBuffers() {
|
||||
static const uint32_t indexData[3] = {
|
||||
|
@ -74,11 +73,11 @@ void init() {
|
|||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetIndexFormat(nxt::IndexFormat::Uint32)
|
||||
|
@ -88,18 +87,16 @@ void init() {
|
|||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
nxt::RenderPassInfo renderPass;
|
||||
GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
|
||||
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.SetIndexBuffer(indexBuffer, 0)
|
||||
.DrawElements(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ nxt::Queue queue;
|
|||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
|
||||
void initBuffers() {
|
||||
static const float vertexData[12] = {
|
||||
|
@ -80,11 +79,11 @@ void init() {
|
|||
.SetInput(1, 2 * sizeof(float), nxt::InputStepMode::Instance)
|
||||
.GetResult();
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
|
@ -93,18 +92,16 @@ void init() {
|
|||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
nxt::RenderPassInfo renderPass;
|
||||
GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
|
||||
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.SetVertexBuffers(1, 1, &instanceBuffer, vertexBufferOffsets)
|
||||
.DrawArrays(3, 4, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@ nxt::Queue queue;
|
|||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::BindGroup bindGroup;
|
||||
|
||||
void initBuffers() {
|
||||
|
@ -121,11 +120,11 @@ void init() {
|
|||
.SetBindGroupLayout(0, bgl)
|
||||
.GetResult();
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -150,19 +149,17 @@ void frame() {
|
|||
if (s.b >= 1.0f) {s.b = 0.0f;}
|
||||
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
nxt::RenderPassInfo renderPass;
|
||||
GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
|
||||
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetBindGroup(0, bindGroup)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.SetIndexBuffer(indexBuffer, 0)
|
||||
.DrawElements(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ nxt::Queue queue;
|
|||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Buffer buffer;
|
||||
nxt::BindGroup bindGroup;
|
||||
|
||||
|
@ -63,11 +62,11 @@ void init() {
|
|||
.SetBindGroupLayout(0, bgl)
|
||||
.GetResult();
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -99,17 +98,15 @@ void frame() {
|
|||
buffer.SetSubData(0, sizeof(s), reinterpret_cast<uint8_t*>(&s));
|
||||
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
nxt::RenderPassInfo renderPass;
|
||||
GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.TransitionBufferUsage(buffer, nxt::BufferUsageBit::Uniform)
|
||||
.SetBindGroup(0, bindGroup)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
|
|
@ -27,7 +27,6 @@ nxt::Queue queue;
|
|||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPass renderpass;
|
||||
|
||||
void initBuffers() {
|
||||
static const float vertexData[12] = {
|
||||
|
@ -69,11 +68,11 @@ void init() {
|
|||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||
.GetResult();
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
|
@ -82,17 +81,15 @@ void init() {
|
|||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
nxt::RenderPassInfo renderPass;
|
||||
GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
|
||||
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
|
|
@ -33,7 +33,6 @@ nxt::SwapChain swapchain;
|
|||
nxt::RenderPipeline pipeline;
|
||||
nxt::RenderPipeline pipelinePost;
|
||||
nxt::BindGroup bindGroup;
|
||||
nxt::RenderPass renderpass;
|
||||
|
||||
void initBuffers() {
|
||||
static const float vertexData[12] = {
|
||||
|
@ -70,19 +69,6 @@ void initTextures() {
|
|||
.GetResult();
|
||||
}
|
||||
|
||||
void initRenderPass() {
|
||||
renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(2)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetFormat(1, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(2)
|
||||
// subpass 0
|
||||
.SubpassSetColorAttachment(0, 0, 0) // -> render target
|
||||
// subpass 1
|
||||
.SubpassSetColorAttachment(1, 0, 1) // -> back buffer
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
void initPipeline() {
|
||||
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
|
@ -106,7 +92,7 @@ void initPipeline() {
|
|||
.GetResult();
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
|
@ -147,7 +133,7 @@ void initPipelinePost() {
|
|||
.GetResult();
|
||||
|
||||
pipelinePost = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 1)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(pl)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -172,7 +158,6 @@ void init() {
|
|||
|
||||
initBuffers();
|
||||
initTextures();
|
||||
initRenderPass();
|
||||
initPipeline();
|
||||
initPipelinePost();
|
||||
}
|
||||
|
@ -180,30 +165,30 @@ void init() {
|
|||
void frame() {
|
||||
nxt::Texture backbuffer = swapchain.GetNextTexture();
|
||||
auto backbufferView = backbuffer.CreateTextureViewBuilder().GetResult();
|
||||
auto framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(640, 480)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.SetAttachment(1, backbufferView)
|
||||
|
||||
nxt::RenderPassInfo renderPass1 = device.CreateRenderPassInfoBuilder()
|
||||
.SetColorAttachment(0, renderTargetView, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
|
||||
nxt::RenderPassInfo renderPass2 = device.CreateRenderPassInfoBuilder()
|
||||
.SetColorAttachment(0, backbufferView, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
|
||||
static const uint32_t vertexBufferOffsets[1] = {0};
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
// renderTarget implicitly locked to to Attachment usage (if not already frozen)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
// renderTarget usage unlocked, but left in Attachment usage
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(pipelinePost)
|
||||
.SetVertexBuffers(0, 1, &vertexBufferQuad, vertexBufferOffsets)
|
||||
.TransitionTextureUsage(renderTarget, nxt::TextureUsageBit::Sampled)
|
||||
.SetBindGroup(0, bindGroup)
|
||||
.DrawArrays(6, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderPass(renderPass1)
|
||||
// renderTarget implicitly locked to to Attachment usage (if not already frozen)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
// renderTarget usage unlocked, but left in Attachment usage
|
||||
.TransitionTextureUsage(renderTarget, nxt::TextureUsageBit::Sampled)
|
||||
.BeginRenderPass(renderPass2)
|
||||
.SetRenderPipeline(pipelinePost)
|
||||
.SetVertexBuffers(0, 1, &vertexBufferQuad, vertexBufferOffsets)
|
||||
.SetBindGroup(0, bindGroup)
|
||||
.DrawArrays(6, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
|
|
@ -134,19 +134,6 @@ nxt::SwapChain GetSwapChain(const nxt::Device &device) {
|
|||
.GetResult();
|
||||
}
|
||||
|
||||
nxt::RenderPass CreateDefaultRenderPass(const nxt::Device& device) {
|
||||
return device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(2)
|
||||
.AttachmentSetFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.AttachmentSetFormat(1, nxt::TextureFormat::D32FloatS8Uint)
|
||||
.AttachmentSetDepthStencilLoadOps(1, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.SubpassSetDepthStencilAttachment(0, 1)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
nxt::TextureView CreateDefaultDepthStencilView(const nxt::Device& device) {
|
||||
auto depthStencilTexture = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
|
@ -160,19 +147,16 @@ nxt::TextureView CreateDefaultDepthStencilView(const nxt::Device& device) {
|
|||
.GetResult();
|
||||
}
|
||||
|
||||
void GetNextFramebuffer(const nxt::Device& device,
|
||||
const nxt::RenderPass& renderpass,
|
||||
const nxt::SwapChain& swapchain,
|
||||
const nxt::TextureView& depthStencilView,
|
||||
nxt::Texture* backbuffer,
|
||||
nxt::Framebuffer* framebuffer) {
|
||||
void GetNextRenderPassInfo(const nxt::Device& device,
|
||||
const nxt::SwapChain& swapchain,
|
||||
const nxt::TextureView& depthStencilView,
|
||||
nxt::Texture* backbuffer,
|
||||
nxt::RenderPassInfo* info) {
|
||||
*backbuffer = swapchain.GetNextTexture();
|
||||
auto backbufferView = backbuffer->CreateTextureViewBuilder().GetResult();
|
||||
*framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(640, 480)
|
||||
.SetAttachment(0, backbufferView)
|
||||
.SetAttachment(1, depthStencilView)
|
||||
*info = device.CreateRenderPassInfoBuilder()
|
||||
.SetColorAttachment(0, backbufferView, nxt::LoadOp::Clear)
|
||||
.SetDepthStencilAttachment(depthStencilView, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
|
|
|
@ -26,11 +26,9 @@ nxt::Device CreateCppNXTDevice();
|
|||
uint64_t GetSwapChainImplementation();
|
||||
nxt::TextureFormat GetPreferredSwapChainTextureFormat();
|
||||
nxt::SwapChain GetSwapChain(const nxt::Device& device);
|
||||
nxt::RenderPass CreateDefaultRenderPass(const nxt::Device& device);
|
||||
nxt::TextureView CreateDefaultDepthStencilView(const nxt::Device& device);
|
||||
void GetNextFramebuffer(const nxt::Device& device,
|
||||
const nxt::RenderPass& renderPass,
|
||||
void GetNextRenderPassInfo(const nxt::Device& device,
|
||||
const nxt::SwapChain& swapchain,
|
||||
const nxt::TextureView& depthStencilView,
|
||||
nxt::Texture* backbuffer,
|
||||
nxt::Framebuffer* framebuffer);
|
||||
nxt::RenderPassInfo* info);
|
||||
|
|
|
@ -79,7 +79,6 @@ nxt::Device device;
|
|||
nxt::Queue queue;
|
||||
nxt::SwapChain swapchain;
|
||||
nxt::TextureView depthStencilView;
|
||||
nxt::RenderPass renderpass;
|
||||
|
||||
nxt::Buffer defaultBuffer;
|
||||
std::map<std::string, nxt::Buffer> buffers;
|
||||
|
@ -291,7 +290,8 @@ namespace {
|
|||
.SetBindGroupLayout(0, bindGroupLayout)
|
||||
.GetResult();
|
||||
auto pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, oVSModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, oFSModule, "main")
|
||||
|
@ -468,7 +468,6 @@ namespace {
|
|||
swapchain.Configure(GetPreferredSwapChainTextureFormat(),
|
||||
nxt::TextureUsageBit::OutputAttachment, 640, 480);
|
||||
|
||||
renderpass = CreateDefaultRenderPass(device);
|
||||
depthStencilView = CreateDefaultDepthStencilView(device);
|
||||
|
||||
initBuffers();
|
||||
|
@ -585,21 +584,18 @@ namespace {
|
|||
|
||||
void frame() {
|
||||
nxt::Texture backbuffer;
|
||||
nxt::Framebuffer framebuffer;
|
||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||
framebuffer.AttachmentSetClearColor(0, 0.3f, 0.4f, 0.5f, 1);
|
||||
nxt::RenderPassInfo renderPass;
|
||||
GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
|
||||
|
||||
const auto& defaultSceneNodes = scene.scenes.at(scene.defaultScene);
|
||||
nxt::CommandBufferBuilder cmd = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass)
|
||||
.Clone();
|
||||
for (const auto& n : defaultSceneNodes) {
|
||||
const auto& node = scene.nodes.at(n);
|
||||
drawNode(cmd, node);
|
||||
}
|
||||
auto commands = cmd.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
auto commands = cmd.EndRenderPass()
|
||||
.GetResult();
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
|
|
152
next.json
152
next.json
|
@ -345,13 +345,9 @@
|
|||
{
|
||||
"name": "begin render pass",
|
||||
"args": [
|
||||
{"name": "render pass", "type": "render pass"},
|
||||
{"name": "framebuffer", "type": "framebuffer"}
|
||||
{"name": "info", "type": "render pass info"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "begin render subpass"
|
||||
},
|
||||
{
|
||||
"name": "copy buffer to buffer",
|
||||
"args": [
|
||||
|
@ -441,9 +437,6 @@
|
|||
{
|
||||
"name": "end render pass"
|
||||
},
|
||||
{
|
||||
"name": "end render subpass"
|
||||
},
|
||||
{
|
||||
"name": "set stencil reference",
|
||||
"args": [
|
||||
|
@ -599,8 +592,8 @@
|
|||
"returns": "depth stencil state builder"
|
||||
},
|
||||
{
|
||||
"name": "create framebuffer builder",
|
||||
"returns": "framebuffer builder"
|
||||
"name": "create render pass info builder",
|
||||
"returns": "render pass info builder"
|
||||
},
|
||||
{
|
||||
"name": "create input state builder",
|
||||
|
@ -622,10 +615,6 @@
|
|||
"name": "create queue builder",
|
||||
"returns": "queue builder"
|
||||
},
|
||||
{
|
||||
"name": "create render pass builder",
|
||||
"returns": "render pass builder"
|
||||
},
|
||||
{
|
||||
"name": "create sampler builder",
|
||||
"returns": "sampler builder"
|
||||
|
@ -725,60 +714,6 @@
|
|||
"float": {
|
||||
"category": "native"
|
||||
},
|
||||
"framebuffer": {
|
||||
"category": "object",
|
||||
"methods": [
|
||||
{
|
||||
"name": "attachment set clear color",
|
||||
"TODO": "determine where to put these methods (probably BeginRenderPass?)",
|
||||
"args": [
|
||||
{"name": "attachment slot", "type": "uint32_t"},
|
||||
{"name": "clear r", "type": "float"},
|
||||
{"name": "clear g", "type": "float"},
|
||||
{"name": "clear b", "type": "float"},
|
||||
{"name": "clear a", "type": "float"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "attachment set clear depth stencil",
|
||||
"TODO": "determine where to put these methods (probably BeginRenderPass?)",
|
||||
"args": [
|
||||
{"name": "attachment slot", "type": "uint32_t"},
|
||||
{"name": "clear depth", "type": "float"},
|
||||
{"name": "clear stencil", "type": "uint32_t"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"framebuffer builder": {
|
||||
"category": "object",
|
||||
"methods": [
|
||||
{
|
||||
"name": "get result",
|
||||
"returns": "framebuffer"
|
||||
},
|
||||
{
|
||||
"name": "set render pass",
|
||||
"args": [
|
||||
{"name": "render pass", "type": "render pass"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set dimensions",
|
||||
"args": [
|
||||
{"name": "width", "type": "uint32_t"},
|
||||
{"name": "height", "type": "uint32_t"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set attachment",
|
||||
"args": [
|
||||
{"name": "attachment slot", "type": "uint32_t"},
|
||||
{"name": "texture view", "type": "texture view"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"index format": {
|
||||
"category": "enum",
|
||||
"values": [
|
||||
|
@ -879,70 +814,51 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"render pass builder": {
|
||||
"render pass info builder": {
|
||||
"category": "object",
|
||||
"TODO": {
|
||||
"attachments": "Also need load op, store op, depth/stencil attachments and depth/stencil ops, and maybe usages for the implicit attachment transitions",
|
||||
"subpasses": "Also need input attachments, resolve attachments, and preserve attachments"
|
||||
},
|
||||
"methods": [
|
||||
{
|
||||
"name": "get result",
|
||||
"returns": "render pass"
|
||||
"returns": "render pass info"
|
||||
},
|
||||
{
|
||||
"name": "set attachment count",
|
||||
"args": [
|
||||
{"name": "attachment count", "type": "uint32_t"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "attachment set format",
|
||||
"TODO": "Also need sample count",
|
||||
"name": "set color attachment",
|
||||
"args": [
|
||||
{"name": "attachment slot", "type": "uint32_t"},
|
||||
{"name": "format", "type": "texture format"}
|
||||
{"name": "texture view", "type": "texture view"},
|
||||
{"name": "load op", "type": "load op"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "attachment set color load op",
|
||||
"name": "set color attachment clear color",
|
||||
"TODO": "determine where to put these methods (probably BeginRenderPass?)",
|
||||
"args": [
|
||||
{"name": "attachment slot", "type": "uint32_t"},
|
||||
{"name": "op", "type": "load op"}
|
||||
{"name": "clear r", "type": "float"},
|
||||
{"name": "clear g", "type": "float"},
|
||||
{"name": "clear b", "type": "float"},
|
||||
{"name": "clear a", "type": "float"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "attachment set depth stencil load ops",
|
||||
"name": "set depth stencil attachment",
|
||||
"args": [
|
||||
{"name": "attachment slot", "type": "uint32_t"},
|
||||
{"name": "depth op", "type": "load op"},
|
||||
{"name": "stencil op", "type": "load op"}
|
||||
{"name": "texture view", "type": "texture view"},
|
||||
{"name": "depth load op", "type": "load op"},
|
||||
{"name": "stencil load op", "type": "load op"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set subpass count",
|
||||
"name": "set depth stencil attachment clear value",
|
||||
"TODO": "determine where to put these methods (probably BeginRenderPass?)",
|
||||
"args": [
|
||||
{"name": "subpass count", "type": "uint32_t"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "subpass set color attachment",
|
||||
"args": [
|
||||
{"name": "subpass index", "type": "uint32_t"},
|
||||
{"name": "output attachment location", "type": "uint32_t"},
|
||||
{"name": "attachment slot", "type": "uint32_t"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "subpass set depth stencil attachment",
|
||||
"args": [
|
||||
{"name": "subpass index", "type": "uint32_t"},
|
||||
{"name": "attachment slot", "type": "uint32_t"}
|
||||
{"name": "clear depth", "type": "float"},
|
||||
{"name": "clear stencil", "type": "uint32_t"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"render pass": {
|
||||
"render pass info": {
|
||||
"category": "object"
|
||||
},
|
||||
"render pipeline": {
|
||||
|
@ -955,6 +871,21 @@
|
|||
"name": "get result",
|
||||
"returns": "render pipeline"
|
||||
},
|
||||
{
|
||||
"name": "set color attachment format",
|
||||
"TODO": "Also need sample count",
|
||||
"args": [
|
||||
{"name": "attachment slot", "type": "uint32_t"},
|
||||
{"name": "format", "type": "texture format"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set depth stencil attachment format",
|
||||
"TODO": "Also need sample count",
|
||||
"args": [
|
||||
{"name": "format", "type": "texture format"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set color attachment blend state",
|
||||
"args": [
|
||||
|
@ -999,13 +930,6 @@
|
|||
{"name": "module", "type": "shader module"},
|
||||
{"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "set subpass",
|
||||
"args": [
|
||||
{"name": "render pass", "type": "render pass"},
|
||||
{"name": "subpass", "type": "uint32_t"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -40,7 +40,8 @@ namespace backend {
|
|||
}
|
||||
|
||||
for (uint32_t binding : IterateBitSet(a.mask)) {
|
||||
if ((a.visibilities[binding] != b.visibilities[binding]) || (a.types[binding] != b.types[binding])) {
|
||||
if ((a.visibilities[binding] != b.visibilities[binding]) ||
|
||||
(a.types[binding] != b.types[binding])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -241,8 +241,6 @@ if (NXT_ENABLE_D3D12)
|
|||
${D3D12_DIR}/DescriptorHeapAllocator.h
|
||||
${D3D12_DIR}/D3D12Backend.cpp
|
||||
${D3D12_DIR}/D3D12Backend.h
|
||||
${D3D12_DIR}/FramebufferD3D12.cpp
|
||||
${D3D12_DIR}/FramebufferD3D12.h
|
||||
${D3D12_DIR}/InputStateD3D12.cpp
|
||||
${D3D12_DIR}/InputStateD3D12.h
|
||||
${D3D12_DIR}/NativeSwapChainImplD3D12.cpp
|
||||
|
@ -251,6 +249,8 @@ if (NXT_ENABLE_D3D12)
|
|||
${D3D12_DIR}/PipelineLayoutD3D12.h
|
||||
${D3D12_DIR}/QueueD3D12.cpp
|
||||
${D3D12_DIR}/QueueD3D12.h
|
||||
${D3D12_DIR}/RenderPassInfoD3D12.cpp
|
||||
${D3D12_DIR}/RenderPassInfoD3D12.h
|
||||
${D3D12_DIR}/RenderPipelineD3D12.cpp
|
||||
${D3D12_DIR}/RenderPipelineD3D12.h
|
||||
${D3D12_DIR}/ResourceAllocator.cpp
|
||||
|
@ -308,8 +308,6 @@ if (NXT_ENABLE_VULKAN)
|
|||
${VULKAN_DIR}/DepthStencilStateVk.h
|
||||
${VULKAN_DIR}/FencedDeleter.cpp
|
||||
${VULKAN_DIR}/FencedDeleter.h
|
||||
${VULKAN_DIR}/FramebufferVk.cpp
|
||||
${VULKAN_DIR}/FramebufferVk.h
|
||||
${VULKAN_DIR}/InputStateVk.cpp
|
||||
${VULKAN_DIR}/InputStateVk.h
|
||||
${VULKAN_DIR}/MemoryAllocator.cpp
|
||||
|
@ -318,8 +316,10 @@ if (NXT_ENABLE_VULKAN)
|
|||
${VULKAN_DIR}/NativeSwapChainImplVk.h
|
||||
${VULKAN_DIR}/PipelineLayoutVk.cpp
|
||||
${VULKAN_DIR}/PipelineLayoutVk.h
|
||||
${VULKAN_DIR}/RenderPassVk.cpp
|
||||
${VULKAN_DIR}/RenderPassVk.h
|
||||
${VULKAN_DIR}/RenderPassCache.cpp
|
||||
${VULKAN_DIR}/RenderPassCache.h
|
||||
${VULKAN_DIR}/RenderPassInfoVk.cpp
|
||||
${VULKAN_DIR}/RenderPassInfoVk.h
|
||||
${VULKAN_DIR}/RenderPipelineVk.cpp
|
||||
${VULKAN_DIR}/RenderPipelineVk.h
|
||||
${VULKAN_DIR}/SamplerVk.cpp
|
||||
|
@ -367,8 +367,6 @@ list(APPEND BACKEND_SOURCES
|
|||
${BACKEND_DIR}/Device.cpp
|
||||
${BACKEND_DIR}/Device.h
|
||||
${BACKEND_DIR}/Forward.h
|
||||
${BACKEND_DIR}/Framebuffer.cpp
|
||||
${BACKEND_DIR}/Framebuffer.h
|
||||
${BACKEND_DIR}/InputState.cpp
|
||||
${BACKEND_DIR}/InputState.h
|
||||
${BACKEND_DIR}/RenderPipeline.cpp
|
||||
|
@ -381,8 +379,8 @@ list(APPEND BACKEND_SOURCES
|
|||
${BACKEND_DIR}/PipelineLayout.h
|
||||
${BACKEND_DIR}/Queue.cpp
|
||||
${BACKEND_DIR}/Queue.h
|
||||
${BACKEND_DIR}/RenderPass.cpp
|
||||
${BACKEND_DIR}/RenderPass.h
|
||||
${BACKEND_DIR}/RenderPassInfo.cpp
|
||||
${BACKEND_DIR}/RenderPassInfo.h
|
||||
${BACKEND_DIR}/RefCounted.cpp
|
||||
${BACKEND_DIR}/RefCounted.h
|
||||
${BACKEND_DIR}/Sampler.cpp
|
||||
|
|
|
@ -162,10 +162,6 @@ namespace backend {
|
|||
BeginRenderPassCmd* begin = commands->NextCommand<BeginRenderPassCmd>();
|
||||
begin->~BeginRenderPassCmd();
|
||||
} break;
|
||||
case Command::BeginRenderSubpass: {
|
||||
BeginRenderSubpassCmd* begin = commands->NextCommand<BeginRenderSubpassCmd>();
|
||||
begin->~BeginRenderSubpassCmd();
|
||||
} break;
|
||||
case Command::CopyBufferToBuffer: {
|
||||
CopyBufferToBufferCmd* copy = commands->NextCommand<CopyBufferToBufferCmd>();
|
||||
copy->~CopyBufferToBufferCmd();
|
||||
|
@ -198,10 +194,6 @@ namespace backend {
|
|||
EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>();
|
||||
cmd->~EndRenderPassCmd();
|
||||
} break;
|
||||
case Command::EndRenderSubpass: {
|
||||
EndRenderSubpassCmd* cmd = commands->NextCommand<EndRenderSubpassCmd>();
|
||||
cmd->~EndRenderSubpassCmd();
|
||||
} break;
|
||||
case Command::SetComputePipeline: {
|
||||
SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>();
|
||||
cmd->~SetComputePipelineCmd();
|
||||
|
@ -269,10 +261,6 @@ namespace backend {
|
|||
commands->NextCommand<BeginRenderPassCmd>();
|
||||
break;
|
||||
|
||||
case Command::BeginRenderSubpass:
|
||||
commands->NextCommand<BeginRenderSubpassCmd>();
|
||||
break;
|
||||
|
||||
case Command::CopyBufferToBuffer:
|
||||
commands->NextCommand<CopyBufferToBufferCmd>();
|
||||
break;
|
||||
|
@ -305,10 +293,6 @@ namespace backend {
|
|||
commands->NextCommand<EndRenderPassCmd>();
|
||||
break;
|
||||
|
||||
case Command::EndRenderSubpass:
|
||||
commands->NextCommand<EndRenderSubpassCmd>();
|
||||
break;
|
||||
|
||||
case Command::SetComputePipeline:
|
||||
commands->NextCommand<SetComputePipelineCmd>();
|
||||
break;
|
||||
|
@ -384,25 +368,8 @@ namespace backend {
|
|||
|
||||
case Command::BeginRenderPass: {
|
||||
BeginRenderPassCmd* cmd = mIterator.NextCommand<BeginRenderPassCmd>();
|
||||
auto* renderPass = cmd->renderPass.Get();
|
||||
auto* framebuffer = cmd->framebuffer.Get();
|
||||
// TODO(kainino@chromium.org): null checks should not be necessary
|
||||
if (renderPass == nullptr) {
|
||||
HandleError("Render pass is invalid");
|
||||
return false;
|
||||
}
|
||||
if (framebuffer == nullptr) {
|
||||
HandleError("Framebuffer is invalid");
|
||||
return false;
|
||||
}
|
||||
if (!mState->BeginRenderPass(renderPass, framebuffer)) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::BeginRenderSubpass: {
|
||||
mIterator.NextCommand<BeginRenderSubpassCmd>();
|
||||
if (!mState->BeginSubpass()) {
|
||||
RenderPassInfoBase* info = cmd->info.Get();
|
||||
if (!mState->BeginRenderPass(info)) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
@ -495,13 +462,6 @@ namespace backend {
|
|||
}
|
||||
} break;
|
||||
|
||||
case Command::EndRenderSubpass: {
|
||||
mIterator.NextCommand<EndRenderSubpassCmd>();
|
||||
if (!mState->EndSubpass()) {
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetComputePipeline: {
|
||||
SetComputePipelineCmd* cmd = mIterator.NextCommand<SetComputePipelineCmd>();
|
||||
ComputePipelineBase* pipeline = cmd->pipeline.Get();
|
||||
|
@ -531,24 +491,24 @@ namespace backend {
|
|||
|
||||
case Command::SetStencilReference: {
|
||||
mIterator.NextCommand<SetStencilReferenceCmd>();
|
||||
if (!mState->HaveRenderSubpass()) {
|
||||
HandleError("Can't set stencil reference without an active render subpass");
|
||||
if (!mState->HaveRenderPass()) {
|
||||
HandleError("Can't set stencil reference without an active render pass");
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetBlendColor: {
|
||||
mIterator.NextCommand<SetBlendColorCmd>();
|
||||
if (!mState->HaveRenderSubpass()) {
|
||||
HandleError("Can't set blend color without an active render subpass");
|
||||
if (!mState->HaveRenderPass()) {
|
||||
HandleError("Can't set blend color without an active render pass");
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Command::SetScissorRect: {
|
||||
mIterator.NextCommand<SetScissorRectCmd>();
|
||||
if (!mState->HaveRenderSubpass()) {
|
||||
HandleError("Can't set scissor rect without an active render subpass");
|
||||
if (!mState->HaveRenderPass()) {
|
||||
HandleError("Can't set scissor rect without an active render pass");
|
||||
return false;
|
||||
}
|
||||
} break;
|
||||
|
@ -618,16 +578,10 @@ namespace backend {
|
|||
mAllocator.Allocate<BeginComputePassCmd>(Command::BeginComputePass);
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::BeginRenderPass(RenderPassBase* renderPass,
|
||||
FramebufferBase* framebuffer) {
|
||||
void CommandBufferBuilder::BeginRenderPass(RenderPassInfoBase* info) {
|
||||
BeginRenderPassCmd* cmd = mAllocator.Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
|
||||
new (cmd) BeginRenderPassCmd;
|
||||
cmd->renderPass = renderPass;
|
||||
cmd->framebuffer = framebuffer;
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::BeginRenderSubpass() {
|
||||
mAllocator.Allocate<BeginRenderSubpassCmd>(Command::BeginRenderSubpass);
|
||||
cmd->info = info;
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::CopyBufferToBuffer(BufferBase* source,
|
||||
|
@ -745,10 +699,6 @@ namespace backend {
|
|||
mAllocator.Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::EndRenderSubpass() {
|
||||
mAllocator.Allocate<EndRenderSubpassCmd>(Command::EndRenderSubpass);
|
||||
}
|
||||
|
||||
void CommandBufferBuilder::SetComputePipeline(ComputePipelineBase* pipeline) {
|
||||
SetComputePipelineCmd* cmd =
|
||||
mAllocator.Allocate<SetComputePipelineCmd>(Command::SetComputePipeline);
|
||||
|
|
|
@ -62,8 +62,7 @@ namespace backend {
|
|||
|
||||
// NXT API
|
||||
void BeginComputePass();
|
||||
void BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer);
|
||||
void BeginRenderSubpass();
|
||||
void BeginRenderPass(RenderPassInfoBase* info);
|
||||
void CopyBufferToBuffer(BufferBase* source,
|
||||
uint32_t sourceOffset,
|
||||
BufferBase* destination,
|
||||
|
@ -102,7 +101,6 @@ namespace backend {
|
|||
uint32_t firstInstance);
|
||||
void EndComputePass();
|
||||
void EndRenderPass();
|
||||
void EndRenderSubpass();
|
||||
void SetPushConstants(nxt::ShaderStageBit stages,
|
||||
uint32_t offset,
|
||||
uint32_t count,
|
||||
|
|
|
@ -19,10 +19,9 @@
|
|||
#include "backend/Buffer.h"
|
||||
#include "backend/ComputePipeline.h"
|
||||
#include "backend/Forward.h"
|
||||
#include "backend/Framebuffer.h"
|
||||
#include "backend/InputState.h"
|
||||
#include "backend/PipelineLayout.h"
|
||||
#include "backend/RenderPass.h"
|
||||
#include "backend/RenderPassInfo.h"
|
||||
#include "backend/RenderPipeline.h"
|
||||
#include "backend/Texture.h"
|
||||
#include "common/Assert.h"
|
||||
|
@ -37,10 +36,6 @@ namespace backend {
|
|||
return mCurrentRenderPass != nullptr;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::HaveRenderSubpass() const {
|
||||
return mAspects[VALIDATION_ASPECT_RENDER_SUBPASS];
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::ValidateCanCopy() const {
|
||||
if (mCurrentRenderPass) {
|
||||
mBuilder->HandleError("Copy cannot occur during a render pass");
|
||||
|
@ -91,7 +86,7 @@ namespace backend {
|
|||
bool CommandBufferStateTracker::ValidateCanDrawArrays() {
|
||||
// TODO(kainino@chromium.org): Check for a current render pass
|
||||
constexpr ValidationAspects requiredAspects =
|
||||
1 << VALIDATION_ASPECT_RENDER_PIPELINE | // implicitly requires RENDER_SUBPASS
|
||||
1 << VALIDATION_ASPECT_RENDER_PIPELINE | // implicitly requires RENDER_PASS
|
||||
1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
|
||||
if ((requiredAspects & ~mAspects).none()) {
|
||||
// Fast return-true path if everything is good
|
||||
|
@ -137,15 +132,16 @@ namespace backend {
|
|||
"SetPushConstants stage must be compute or 0 in compute passes");
|
||||
return false;
|
||||
}
|
||||
} else if (mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
|
||||
} else if (mAspects[VALIDATION_ASPECT_RENDER_PASS]) {
|
||||
if (stages & ~(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
|
||||
mBuilder->HandleError(
|
||||
"SetPushConstants stage must be a subset if (vertex|fragment) in subpasses");
|
||||
"SetPushConstants stage must be a subset if (vertex|fragment) in render "
|
||||
"passes");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
mBuilder->HandleError(
|
||||
"PushConstants must be set in either compute passes or subpasses");
|
||||
"PushConstants must be set in either compute passes or render passes");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -170,64 +166,7 @@ namespace backend {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::BeginSubpass() {
|
||||
if (mCurrentRenderPass == nullptr) {
|
||||
mBuilder->HandleError("Can't begin a subpass without an active render pass");
|
||||
return false;
|
||||
}
|
||||
if (mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
|
||||
mBuilder->HandleError("Can't begin a subpass without ending the previous subpass");
|
||||
return false;
|
||||
}
|
||||
if (mCurrentSubpass >= mCurrentRenderPass->GetSubpassCount()) {
|
||||
mBuilder->HandleError("Can't begin a subpass beyond the last subpass");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& subpassInfo = mCurrentRenderPass->GetSubpassInfo(mCurrentSubpass);
|
||||
for (auto location : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
||||
auto attachmentSlot = subpassInfo.colorAttachments[location];
|
||||
auto* tv = mCurrentFramebuffer->GetTextureView(attachmentSlot);
|
||||
auto* texture = tv->GetTexture();
|
||||
if (!EnsureTextureUsage(texture, nxt::TextureUsageBit::OutputAttachment)) {
|
||||
mBuilder->HandleError("Unable to ensure texture has OutputAttachment usage");
|
||||
return false;
|
||||
}
|
||||
mTexturesAttached.insert(texture);
|
||||
}
|
||||
|
||||
mAspects.set(VALIDATION_ASPECT_RENDER_SUBPASS);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::EndSubpass() {
|
||||
if (!mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
|
||||
mBuilder->HandleError("Can't end a subpass without beginning one");
|
||||
return false;
|
||||
}
|
||||
ASSERT(mCurrentRenderPass != nullptr);
|
||||
|
||||
auto& subpassInfo = mCurrentRenderPass->GetSubpassInfo(mCurrentSubpass);
|
||||
for (auto location : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
||||
auto attachmentSlot = subpassInfo.colorAttachments[location];
|
||||
auto* tv = mCurrentFramebuffer->GetTextureView(attachmentSlot);
|
||||
auto* texture = tv->GetTexture();
|
||||
if (texture->IsFrozen()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Everything in mTexturesAttached should be for the current render subpass.
|
||||
mTexturesAttached.clear();
|
||||
|
||||
mCurrentSubpass += 1;
|
||||
mInputsSet.reset();
|
||||
mAspects.reset(VALIDATION_ASPECT_RENDER_SUBPASS);
|
||||
UnsetPipeline();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandBufferStateTracker::BeginRenderPass(RenderPassBase* renderPass,
|
||||
FramebufferBase* framebuffer) {
|
||||
bool CommandBufferStateTracker::BeginRenderPass(RenderPassInfoBase* info) {
|
||||
if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
|
||||
mBuilder->HandleError("Cannot begin a render pass while a compute pass is active");
|
||||
return false;
|
||||
|
@ -236,15 +175,27 @@ namespace backend {
|
|||
mBuilder->HandleError("A render pass is already active");
|
||||
return false;
|
||||
}
|
||||
ASSERT(!mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]);
|
||||
if (!framebuffer->GetRenderPass()->IsCompatibleWith(renderPass)) {
|
||||
mBuilder->HandleError("Framebuffer is incompatible with this render pass");
|
||||
return false;
|
||||
|
||||
mCurrentRenderPass = info;
|
||||
mAspects.set(VALIDATION_ASPECT_RENDER_PASS);
|
||||
|
||||
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
|
||||
TextureBase* texture = info->GetColorAttachment(i).view->GetTexture();
|
||||
if (!EnsureTextureUsage(texture, nxt::TextureUsageBit::OutputAttachment)) {
|
||||
mBuilder->HandleError("Unable to ensure texture has OutputAttachment usage");
|
||||
return false;
|
||||
}
|
||||
mTexturesAttached.insert(texture);
|
||||
}
|
||||
|
||||
mCurrentRenderPass = renderPass;
|
||||
mCurrentFramebuffer = framebuffer;
|
||||
mCurrentSubpass = 0;
|
||||
if (info->HasDepthStencilAttachment()) {
|
||||
TextureBase* texture = info->GetDepthStencilAttachment().view->GetTexture();
|
||||
if (!EnsureTextureUsage(texture, nxt::TextureUsageBit::OutputAttachment)) {
|
||||
mBuilder->HandleError("Unable to ensure texture has OutputAttachment usage");
|
||||
return false;
|
||||
}
|
||||
mTexturesAttached.insert(texture);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -254,16 +205,15 @@ namespace backend {
|
|||
mBuilder->HandleError("No render pass is currently active");
|
||||
return false;
|
||||
}
|
||||
if (mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
|
||||
mBuilder->HandleError("Can't end a render pass while a subpass is active");
|
||||
return false;
|
||||
}
|
||||
if (mCurrentSubpass < mCurrentRenderPass->GetSubpassCount() - 1) {
|
||||
mBuilder->HandleError("Can't end a render pass before the last subpass");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everything in mTexturesAttached should be for the current render pass.
|
||||
mTexturesAttached.clear();
|
||||
|
||||
mInputsSet.reset();
|
||||
UnsetPipeline();
|
||||
|
||||
mAspects.reset(VALIDATION_ASPECT_RENDER_PASS);
|
||||
mCurrentRenderPass = nullptr;
|
||||
mCurrentFramebuffer = nullptr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -284,11 +234,11 @@ namespace backend {
|
|||
}
|
||||
|
||||
bool CommandBufferStateTracker::SetRenderPipeline(RenderPipelineBase* pipeline) {
|
||||
if (!mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
|
||||
mBuilder->HandleError("A render subpass must be active when a render pipeline is set");
|
||||
if (!mAspects[VALIDATION_ASPECT_RENDER_PASS]) {
|
||||
mBuilder->HandleError("A render pass must be active when a render pipeline is set");
|
||||
return false;
|
||||
}
|
||||
if (!pipeline->GetRenderPass()->IsCompatibleWith(mCurrentRenderPass)) {
|
||||
if (!pipeline->IsCompatibleWith(mCurrentRenderPass)) {
|
||||
mBuilder->HandleError("Pipeline is incompatible with this render pass");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ namespace backend {
|
|||
|
||||
// Non-state-modifying validation functions
|
||||
bool HaveRenderPass() const;
|
||||
bool HaveRenderSubpass() const;
|
||||
bool ValidateCanCopy() const;
|
||||
bool ValidateCanUseBufferAs(BufferBase* buffer, nxt::BufferUsageBit usage) const;
|
||||
bool ValidateCanUseTextureAs(TextureBase* texture, nxt::TextureUsageBit usage) const;
|
||||
|
@ -43,9 +42,7 @@ namespace backend {
|
|||
// State-modifying methods
|
||||
bool BeginComputePass();
|
||||
bool EndComputePass();
|
||||
bool BeginSubpass();
|
||||
bool EndSubpass();
|
||||
bool BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer);
|
||||
bool BeginRenderPass(RenderPassInfoBase* info);
|
||||
bool EndRenderPass();
|
||||
bool SetComputePipeline(ComputePipelineBase* pipeline);
|
||||
bool SetRenderPipeline(RenderPipelineBase* pipeline);
|
||||
|
@ -70,7 +67,7 @@ namespace backend {
|
|||
VALIDATION_ASPECT_BIND_GROUPS,
|
||||
VALIDATION_ASPECT_VERTEX_BUFFERS,
|
||||
VALIDATION_ASPECT_INDEX_BUFFER,
|
||||
VALIDATION_ASPECT_RENDER_SUBPASS,
|
||||
VALIDATION_ASPECT_RENDER_PASS,
|
||||
VALIDATION_ASPECT_COMPUTE_PASS,
|
||||
|
||||
VALIDATION_ASPECT_COUNT
|
||||
|
@ -109,9 +106,7 @@ namespace backend {
|
|||
std::map<BufferBase*, nxt::BufferUsageBit> mMostRecentBufferUsages;
|
||||
std::map<TextureBase*, nxt::TextureUsageBit> mMostRecentTextureUsages;
|
||||
|
||||
RenderPassBase* mCurrentRenderPass = nullptr;
|
||||
FramebufferBase* mCurrentFramebuffer = nullptr;
|
||||
uint32_t mCurrentSubpass = 0;
|
||||
RenderPassInfoBase* mCurrentRenderPass = nullptr;
|
||||
};
|
||||
} // namespace backend
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
#ifndef BACKEND_COMMANDS_H_
|
||||
#define BACKEND_COMMANDS_H_
|
||||
|
||||
#include "backend/Framebuffer.h"
|
||||
#include "backend/RenderPass.h"
|
||||
#include "backend/RenderPassInfo.h"
|
||||
#include "backend/Texture.h"
|
||||
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
@ -30,7 +29,6 @@ namespace backend {
|
|||
enum class Command {
|
||||
BeginComputePass,
|
||||
BeginRenderPass,
|
||||
BeginRenderSubpass,
|
||||
CopyBufferToBuffer,
|
||||
CopyBufferToTexture,
|
||||
CopyTextureToBuffer,
|
||||
|
@ -39,7 +37,6 @@ namespace backend {
|
|||
DrawElements,
|
||||
EndComputePass,
|
||||
EndRenderPass,
|
||||
EndRenderSubpass,
|
||||
SetComputePipeline,
|
||||
SetRenderPipeline,
|
||||
SetPushConstants,
|
||||
|
@ -56,12 +53,9 @@ namespace backend {
|
|||
struct BeginComputePassCmd {};
|
||||
|
||||
struct BeginRenderPassCmd {
|
||||
Ref<RenderPassBase> renderPass;
|
||||
Ref<FramebufferBase> framebuffer;
|
||||
Ref<RenderPassInfoBase> info;
|
||||
};
|
||||
|
||||
struct BeginRenderSubpassCmd {};
|
||||
|
||||
struct BufferCopyLocation {
|
||||
Ref<BufferBase> buffer;
|
||||
uint32_t offset;
|
||||
|
@ -116,8 +110,6 @@ namespace backend {
|
|||
|
||||
struct EndRenderPassCmd {};
|
||||
|
||||
struct EndRenderSubpassCmd {};
|
||||
|
||||
struct SetComputePipelineCmd {
|
||||
Ref<ComputePipelineBase> pipeline;
|
||||
};
|
||||
|
|
|
@ -21,11 +21,10 @@
|
|||
#include "backend/CommandBuffer.h"
|
||||
#include "backend/ComputePipeline.h"
|
||||
#include "backend/DepthStencilState.h"
|
||||
#include "backend/Framebuffer.h"
|
||||
#include "backend/InputState.h"
|
||||
#include "backend/PipelineLayout.h"
|
||||
#include "backend/Queue.h"
|
||||
#include "backend/RenderPass.h"
|
||||
#include "backend/RenderPassInfo.h"
|
||||
#include "backend/RenderPipeline.h"
|
||||
#include "backend/Sampler.h"
|
||||
#include "backend/ShaderModule.h"
|
||||
|
@ -116,9 +115,6 @@ namespace backend {
|
|||
DepthStencilStateBuilder* DeviceBase::CreateDepthStencilStateBuilder() {
|
||||
return new DepthStencilStateBuilder(this);
|
||||
}
|
||||
FramebufferBuilder* DeviceBase::CreateFramebufferBuilder() {
|
||||
return new FramebufferBuilder(this);
|
||||
}
|
||||
InputStateBuilder* DeviceBase::CreateInputStateBuilder() {
|
||||
return new InputStateBuilder(this);
|
||||
}
|
||||
|
@ -128,8 +124,8 @@ namespace backend {
|
|||
QueueBuilder* DeviceBase::CreateQueueBuilder() {
|
||||
return new QueueBuilder(this);
|
||||
}
|
||||
RenderPassBuilder* DeviceBase::CreateRenderPassBuilder() {
|
||||
return new RenderPassBuilder(this);
|
||||
RenderPassInfoBuilder* DeviceBase::CreateRenderPassInfoBuilder() {
|
||||
return new RenderPassInfoBuilder(this);
|
||||
}
|
||||
RenderPipelineBuilder* DeviceBase::CreateRenderPipelineBuilder() {
|
||||
return new RenderPipelineBuilder(this);
|
||||
|
|
|
@ -43,11 +43,10 @@ namespace backend {
|
|||
virtual ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) = 0;
|
||||
virtual DepthStencilStateBase* CreateDepthStencilState(
|
||||
DepthStencilStateBuilder* builder) = 0;
|
||||
virtual FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) = 0;
|
||||
virtual InputStateBase* CreateInputState(InputStateBuilder* builder) = 0;
|
||||
virtual PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) = 0;
|
||||
virtual QueueBase* CreateQueue(QueueBuilder* builder) = 0;
|
||||
virtual RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) = 0;
|
||||
virtual RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) = 0;
|
||||
virtual RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) = 0;
|
||||
virtual SamplerBase* CreateSampler(SamplerBuilder* builder) = 0;
|
||||
virtual ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) = 0;
|
||||
|
@ -83,11 +82,10 @@ namespace backend {
|
|||
CommandBufferBuilder* CreateCommandBufferBuilder();
|
||||
ComputePipelineBuilder* CreateComputePipelineBuilder();
|
||||
DepthStencilStateBuilder* CreateDepthStencilStateBuilder();
|
||||
FramebufferBuilder* CreateFramebufferBuilder();
|
||||
InputStateBuilder* CreateInputStateBuilder();
|
||||
PipelineLayoutBuilder* CreatePipelineLayoutBuilder();
|
||||
QueueBuilder* CreateQueueBuilder();
|
||||
RenderPassBuilder* CreateRenderPassBuilder();
|
||||
RenderPassInfoBuilder* CreateRenderPassInfoBuilder();
|
||||
RenderPipelineBuilder* CreateRenderPipelineBuilder();
|
||||
SamplerBuilder* CreateSamplerBuilder();
|
||||
ShaderModuleBuilder* CreateShaderModuleBuilder();
|
||||
|
|
|
@ -35,16 +35,14 @@ namespace backend {
|
|||
class CommandBufferBuilder;
|
||||
class DepthStencilStateBase;
|
||||
class DepthStencilStateBuilder;
|
||||
class FramebufferBase;
|
||||
class FramebufferBuilder;
|
||||
class InputStateBase;
|
||||
class InputStateBuilder;
|
||||
class PipelineLayoutBase;
|
||||
class PipelineLayoutBuilder;
|
||||
class QueueBase;
|
||||
class QueueBuilder;
|
||||
class RenderPassBase;
|
||||
class RenderPassBuilder;
|
||||
class RenderPassInfoBase;
|
||||
class RenderPassInfoBuilder;
|
||||
class RenderPipelineBase;
|
||||
class RenderPipelineBuilder;
|
||||
class SamplerBase;
|
||||
|
|
|
@ -1,184 +0,0 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "backend/Framebuffer.h"
|
||||
|
||||
#include "backend/Buffer.h"
|
||||
#include "backend/Device.h"
|
||||
#include "backend/RenderPass.h"
|
||||
#include "backend/Texture.h"
|
||||
#include "common/Assert.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
// Framebuffer
|
||||
|
||||
FramebufferBase::FramebufferBase(FramebufferBuilder* builder)
|
||||
: mDevice(builder->mDevice),
|
||||
mRenderPass(std::move(builder->mRenderPass)),
|
||||
mWidth(builder->mWidth),
|
||||
mHeight(builder->mHeight),
|
||||
mTextureViews(std::move(builder->mTextureViews)),
|
||||
mClearColors(mTextureViews.size()),
|
||||
mClearDepthStencils(mTextureViews.size()) {
|
||||
}
|
||||
|
||||
DeviceBase* FramebufferBase::GetDevice() {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
RenderPassBase* FramebufferBase::GetRenderPass() {
|
||||
return mRenderPass.Get();
|
||||
}
|
||||
|
||||
TextureViewBase* FramebufferBase::GetTextureView(uint32_t attachmentSlot) {
|
||||
ASSERT(attachmentSlot < mTextureViews.size());
|
||||
return mTextureViews[attachmentSlot].Get();
|
||||
}
|
||||
|
||||
FramebufferBase::ClearColor FramebufferBase::GetClearColor(uint32_t attachmentSlot) {
|
||||
ASSERT(attachmentSlot < mClearColors.size());
|
||||
return mClearColors[attachmentSlot];
|
||||
}
|
||||
|
||||
FramebufferBase::ClearDepthStencil FramebufferBase::GetClearDepthStencil(
|
||||
uint32_t attachmentSlot) {
|
||||
ASSERT(attachmentSlot < mClearDepthStencils.size());
|
||||
return mClearDepthStencils[attachmentSlot];
|
||||
}
|
||||
|
||||
uint32_t FramebufferBase::GetWidth() const {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
uint32_t FramebufferBase::GetHeight() const {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
void FramebufferBase::AttachmentSetClearColor(uint32_t attachmentSlot,
|
||||
float clearR,
|
||||
float clearG,
|
||||
float clearB,
|
||||
float clearA) {
|
||||
if (attachmentSlot >= mRenderPass->GetAttachmentCount()) {
|
||||
mDevice->HandleError("Framebuffer attachment out of bounds");
|
||||
return;
|
||||
}
|
||||
ASSERT(attachmentSlot < mClearColors.size());
|
||||
auto& c = mClearColors[attachmentSlot];
|
||||
c.color[0] = clearR;
|
||||
c.color[1] = clearG;
|
||||
c.color[2] = clearB;
|
||||
c.color[3] = clearA;
|
||||
}
|
||||
|
||||
void FramebufferBase::AttachmentSetClearDepthStencil(uint32_t attachmentSlot,
|
||||
float clearDepth,
|
||||
uint32_t clearStencil) {
|
||||
if (attachmentSlot >= mRenderPass->GetAttachmentCount()) {
|
||||
mDevice->HandleError("Framebuffer attachment out of bounds");
|
||||
return;
|
||||
}
|
||||
ASSERT(attachmentSlot < mClearDepthStencils.size());
|
||||
auto& c = mClearDepthStencils[attachmentSlot];
|
||||
c.depth = clearDepth;
|
||||
c.stencil = clearStencil;
|
||||
}
|
||||
|
||||
// FramebufferBuilder
|
||||
|
||||
enum FramebufferSetProperties {
|
||||
FRAMEBUFFER_PROPERTY_RENDER_PASS = 0x1,
|
||||
FRAMEBUFFER_PROPERTY_DIMENSIONS = 0x2,
|
||||
};
|
||||
|
||||
FramebufferBuilder::FramebufferBuilder(DeviceBase* device) : Builder(device) {
|
||||
}
|
||||
|
||||
FramebufferBase* FramebufferBuilder::GetResultImpl() {
|
||||
constexpr int requiredProperties =
|
||||
FRAMEBUFFER_PROPERTY_RENDER_PASS | FRAMEBUFFER_PROPERTY_DIMENSIONS;
|
||||
if ((mPropertiesSet & requiredProperties) != requiredProperties) {
|
||||
HandleError("Framebuffer missing properties");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (auto& textureView : mTextureViews) {
|
||||
if (!textureView) {
|
||||
HandleError("Framebuffer attachment not set");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// TODO(cwallez@chromium.org): Adjust for the mip-level once that is supported.
|
||||
if (textureView->GetTexture()->GetWidth() != mWidth ||
|
||||
textureView->GetTexture()->GetHeight() != mHeight) {
|
||||
HandleError("Framebuffer size doesn't match attachment size");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return mDevice->CreateFramebuffer(this);
|
||||
}
|
||||
|
||||
void FramebufferBuilder::SetRenderPass(RenderPassBase* renderPass) {
|
||||
if ((mPropertiesSet & FRAMEBUFFER_PROPERTY_RENDER_PASS) != 0) {
|
||||
HandleError("Framebuffer render pass property set multiple times");
|
||||
return;
|
||||
}
|
||||
// TODO(kainino@chromium.org): null checks should not be necessary
|
||||
if (renderPass == nullptr) {
|
||||
HandleError("Render pass invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
mRenderPass = renderPass;
|
||||
mTextureViews.resize(renderPass->GetAttachmentCount());
|
||||
mPropertiesSet |= FRAMEBUFFER_PROPERTY_RENDER_PASS;
|
||||
}
|
||||
|
||||
void FramebufferBuilder::SetDimensions(uint32_t width, uint32_t height) {
|
||||
if ((mPropertiesSet & FRAMEBUFFER_PROPERTY_DIMENSIONS) != 0) {
|
||||
HandleError("Framebuffer dimensions property set multiple times");
|
||||
return;
|
||||
}
|
||||
|
||||
mWidth = width;
|
||||
mHeight = height;
|
||||
mPropertiesSet |= FRAMEBUFFER_PROPERTY_DIMENSIONS;
|
||||
}
|
||||
|
||||
void FramebufferBuilder::SetAttachment(uint32_t attachmentSlot, TextureViewBase* textureView) {
|
||||
if ((mPropertiesSet & FRAMEBUFFER_PROPERTY_RENDER_PASS) == 0) {
|
||||
HandleError("Render pass must be set before framebuffer attachments");
|
||||
return;
|
||||
}
|
||||
if (attachmentSlot >= mTextureViews.size()) {
|
||||
HandleError("Attachment slot out of bounds");
|
||||
return;
|
||||
}
|
||||
if (mTextureViews[attachmentSlot]) {
|
||||
HandleError("Framebuffer attachment[i] set multiple times");
|
||||
return;
|
||||
}
|
||||
const auto& attachmentInfo = mRenderPass->GetAttachmentInfo(attachmentSlot);
|
||||
const auto* texture = textureView->GetTexture();
|
||||
if (attachmentInfo.format != texture->GetFormat()) {
|
||||
HandleError("Texture format does not match attachment format");
|
||||
return;
|
||||
}
|
||||
// TODO(kainino@chromium.org): also check attachment samples, etc.
|
||||
|
||||
mTextureViews[attachmentSlot] = textureView;
|
||||
}
|
||||
} // namespace backend
|
|
@ -1,93 +0,0 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef BACKEND_FRAMEBUFFER_H_
|
||||
#define BACKEND_FRAMEBUFFER_H_
|
||||
|
||||
#include "backend/Builder.h"
|
||||
#include "backend/Forward.h"
|
||||
#include "backend/RefCounted.h"
|
||||
#include "backend/Texture.h"
|
||||
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace backend {
|
||||
|
||||
class FramebufferBase : public RefCounted {
|
||||
public:
|
||||
struct ClearColor {
|
||||
float color[4] = {};
|
||||
};
|
||||
|
||||
struct ClearDepthStencil {
|
||||
float depth = 1.0f;
|
||||
uint32_t stencil = 0;
|
||||
};
|
||||
|
||||
FramebufferBase(FramebufferBuilder* builder);
|
||||
|
||||
DeviceBase* GetDevice();
|
||||
RenderPassBase* GetRenderPass();
|
||||
TextureViewBase* GetTextureView(uint32_t attachmentSlot);
|
||||
ClearColor GetClearColor(uint32_t attachmentSlot);
|
||||
ClearDepthStencil GetClearDepthStencil(uint32_t attachmentSlot);
|
||||
uint32_t GetWidth() const;
|
||||
uint32_t GetHeight() const;
|
||||
|
||||
// NXT API
|
||||
void AttachmentSetClearColor(uint32_t attachmentSlot,
|
||||
float clearR,
|
||||
float clearG,
|
||||
float clearB,
|
||||
float clearA);
|
||||
void AttachmentSetClearDepthStencil(uint32_t attachmentSlot,
|
||||
float clearDepth,
|
||||
uint32_t clearStencil);
|
||||
|
||||
private:
|
||||
DeviceBase* mDevice;
|
||||
Ref<RenderPassBase> mRenderPass;
|
||||
uint32_t mWidth = 0;
|
||||
uint32_t mHeight = 0;
|
||||
std::vector<Ref<TextureViewBase>> mTextureViews;
|
||||
std::vector<ClearColor> mClearColors;
|
||||
std::vector<ClearDepthStencil> mClearDepthStencils;
|
||||
};
|
||||
|
||||
class FramebufferBuilder : public Builder<FramebufferBase> {
|
||||
public:
|
||||
FramebufferBuilder(DeviceBase* device);
|
||||
|
||||
// NXT API
|
||||
FramebufferBase* GetResultImpl() override;
|
||||
void SetRenderPass(RenderPassBase* renderPass);
|
||||
void SetDimensions(uint32_t width, uint32_t height);
|
||||
void SetAttachment(uint32_t attachmentSlot, TextureViewBase* textureView);
|
||||
|
||||
private:
|
||||
friend class FramebufferBase;
|
||||
|
||||
Ref<RenderPassBase> mRenderPass;
|
||||
uint32_t mWidth = 0;
|
||||
uint32_t mHeight = 0;
|
||||
std::vector<Ref<TextureViewBase>> mTextureViews;
|
||||
int mPropertiesSet = 0;
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
|
||||
#endif // BACKEND_FRAMEBUFFER_H_
|
|
@ -18,7 +18,6 @@
|
|||
#include "backend/Device.h"
|
||||
#include "backend/InputState.h"
|
||||
#include "backend/PipelineLayout.h"
|
||||
#include "backend/RenderPass.h"
|
||||
#include "backend/ShaderModule.h"
|
||||
|
||||
namespace backend {
|
||||
|
|
|
@ -1,252 +0,0 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "backend/RenderPass.h"
|
||||
|
||||
#include "backend/Buffer.h"
|
||||
#include "backend/Device.h"
|
||||
#include "backend/Texture.h"
|
||||
#include "common/Assert.h"
|
||||
#include "common/BitSetIterator.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
// RenderPass
|
||||
|
||||
RenderPassBase::RenderPassBase(RenderPassBuilder* builder)
|
||||
: mAttachments(std::move(builder->mAttachments)),
|
||||
mSubpasses(std::move(builder->mSubpasses)) {
|
||||
for (uint32_t s = 0; s < GetSubpassCount(); ++s) {
|
||||
const auto& subpass = GetSubpassInfo(s);
|
||||
for (auto location : IterateBitSet(subpass.colorAttachmentsSet)) {
|
||||
auto attachmentSlot = subpass.colorAttachments[location];
|
||||
auto& firstSubpass = mAttachments[attachmentSlot].firstSubpass;
|
||||
if (firstSubpass == UINT32_MAX) {
|
||||
firstSubpass = s;
|
||||
}
|
||||
}
|
||||
if (subpass.depthStencilAttachmentSet) {
|
||||
auto attachmentSlot = subpass.depthStencilAttachment;
|
||||
auto& firstSubpass = mAttachments[attachmentSlot].firstSubpass;
|
||||
if (firstSubpass == UINT32_MAX) {
|
||||
firstSubpass = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t RenderPassBase::GetAttachmentCount() const {
|
||||
return static_cast<uint32_t>(mAttachments.size());
|
||||
}
|
||||
|
||||
const RenderPassBase::AttachmentInfo& RenderPassBase::GetAttachmentInfo(
|
||||
uint32_t attachment) const {
|
||||
ASSERT(attachment < mAttachments.size());
|
||||
return mAttachments[attachment];
|
||||
}
|
||||
|
||||
uint32_t RenderPassBase::GetSubpassCount() const {
|
||||
return static_cast<uint32_t>(mSubpasses.size());
|
||||
}
|
||||
|
||||
const RenderPassBase::SubpassInfo& RenderPassBase::GetSubpassInfo(uint32_t subpass) const {
|
||||
ASSERT(subpass < mSubpasses.size());
|
||||
return mSubpasses[subpass];
|
||||
}
|
||||
|
||||
bool RenderPassBase::IsCompatibleWith(const RenderPassBase* other) const {
|
||||
// TODO(kainino@chromium.org): This check is overly strict; need actual
|
||||
// compatibility checking (different load and store ops, etc.)
|
||||
return other == this;
|
||||
}
|
||||
|
||||
// RenderPassBuilder
|
||||
|
||||
enum RenderPassSetProperties {
|
||||
RENDERPASS_PROPERTY_ATTACHMENT_COUNT = 0x1,
|
||||
RENDERPASS_PROPERTY_SUBPASS_COUNT = 0x2,
|
||||
};
|
||||
|
||||
RenderPassBuilder::RenderPassBuilder(DeviceBase* device) : Builder(device), mSubpasses(1) {
|
||||
}
|
||||
|
||||
RenderPassBase* RenderPassBuilder::GetResultImpl() {
|
||||
constexpr int requiredProperties =
|
||||
RENDERPASS_PROPERTY_ATTACHMENT_COUNT | RENDERPASS_PROPERTY_SUBPASS_COUNT;
|
||||
if ((mPropertiesSet & requiredProperties) != requiredProperties) {
|
||||
HandleError("Render pass missing properties");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (const auto& prop : mAttachmentProperties) {
|
||||
if (!prop.all()) {
|
||||
HandleError("A render pass attachment is missing some property");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& subpass : mSubpasses) {
|
||||
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
|
||||
uint32_t slot = subpass.colorAttachments[location];
|
||||
if (TextureFormatHasDepthOrStencil(mAttachments[slot].format)) {
|
||||
HandleError("Render pass color attachment is not of a color format");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (subpass.depthStencilAttachmentSet) {
|
||||
uint32_t slot = subpass.depthStencilAttachment;
|
||||
if (!TextureFormatHasDepthOrStencil(mAttachments[slot].format)) {
|
||||
HandleError(
|
||||
"Render pass depth/stencil attachment is not of a depth/stencil format");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mDevice->CreateRenderPass(this);
|
||||
}
|
||||
|
||||
void RenderPassBuilder::SetAttachmentCount(uint32_t attachmentCount) {
|
||||
if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) != 0) {
|
||||
HandleError("Render pass attachment count property set multiple times");
|
||||
return;
|
||||
}
|
||||
|
||||
mAttachmentProperties.resize(attachmentCount);
|
||||
mAttachments.resize(attachmentCount);
|
||||
mPropertiesSet |= RENDERPASS_PROPERTY_ATTACHMENT_COUNT;
|
||||
}
|
||||
|
||||
void RenderPassBuilder::AttachmentSetFormat(uint32_t attachmentSlot,
|
||||
nxt::TextureFormat format) {
|
||||
if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
|
||||
HandleError("Render pass attachment count not set yet");
|
||||
return;
|
||||
}
|
||||
if (attachmentSlot >= mAttachments.size()) {
|
||||
HandleError("Render pass attachment slot out of bounds");
|
||||
return;
|
||||
}
|
||||
if (mAttachmentProperties[attachmentSlot][ATTACHMENT_PROPERTY_FORMAT]) {
|
||||
HandleError("Render pass attachment format already set");
|
||||
return;
|
||||
}
|
||||
|
||||
mAttachments[attachmentSlot].format = format;
|
||||
mAttachmentProperties[attachmentSlot].set(ATTACHMENT_PROPERTY_FORMAT);
|
||||
}
|
||||
|
||||
void RenderPassBuilder::AttachmentSetColorLoadOp(uint32_t attachmentSlot, nxt::LoadOp op) {
|
||||
if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
|
||||
HandleError("Render pass attachment count not set yet");
|
||||
return;
|
||||
}
|
||||
if (attachmentSlot >= mAttachments.size()) {
|
||||
HandleError("Render pass attachment slot out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
mAttachments[attachmentSlot].colorLoadOp = op;
|
||||
}
|
||||
|
||||
void RenderPassBuilder::AttachmentSetDepthStencilLoadOps(uint32_t attachmentSlot,
|
||||
nxt::LoadOp depthOp,
|
||||
nxt::LoadOp stencilOp) {
|
||||
if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
|
||||
HandleError("Render pass attachment count not set yet");
|
||||
return;
|
||||
}
|
||||
if (attachmentSlot >= mAttachments.size()) {
|
||||
HandleError("Render pass attachment slot out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
mAttachments[attachmentSlot].depthLoadOp = depthOp;
|
||||
mAttachments[attachmentSlot].stencilLoadOp = stencilOp;
|
||||
}
|
||||
|
||||
void RenderPassBuilder::SetSubpassCount(uint32_t subpassCount) {
|
||||
if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) != 0) {
|
||||
HandleError("Render pass subpass count property set multiple times");
|
||||
return;
|
||||
}
|
||||
if (subpassCount < 1) {
|
||||
HandleError("Render pass cannot have fewer than one subpass");
|
||||
return;
|
||||
}
|
||||
|
||||
mSubpasses.resize(subpassCount);
|
||||
mPropertiesSet |= RENDERPASS_PROPERTY_SUBPASS_COUNT;
|
||||
}
|
||||
|
||||
void RenderPassBuilder::SubpassSetColorAttachment(uint32_t subpass,
|
||||
uint32_t outputAttachmentLocation,
|
||||
uint32_t attachmentSlot) {
|
||||
if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) == 0) {
|
||||
HandleError("Render pass subpass count not set yet");
|
||||
return;
|
||||
}
|
||||
if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
|
||||
HandleError("Render pass attachment count not set yet");
|
||||
return;
|
||||
}
|
||||
if (subpass >= mSubpasses.size()) {
|
||||
HandleError("Subpass index out of bounds");
|
||||
return;
|
||||
}
|
||||
if (outputAttachmentLocation >= kMaxColorAttachments) {
|
||||
HandleError("Subpass output attachment location out of bounds");
|
||||
return;
|
||||
}
|
||||
if (attachmentSlot >= mAttachments.size()) {
|
||||
HandleError("Subpass attachment slot out of bounds");
|
||||
return;
|
||||
}
|
||||
if (mSubpasses[subpass].colorAttachmentsSet[outputAttachmentLocation]) {
|
||||
HandleError("Subpass color attachment already set");
|
||||
return;
|
||||
}
|
||||
|
||||
mSubpasses[subpass].colorAttachmentsSet.set(outputAttachmentLocation);
|
||||
mSubpasses[subpass].colorAttachments[outputAttachmentLocation] = attachmentSlot;
|
||||
}
|
||||
|
||||
void RenderPassBuilder::SubpassSetDepthStencilAttachment(uint32_t subpass,
|
||||
uint32_t attachmentSlot) {
|
||||
if ((mPropertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) == 0) {
|
||||
HandleError("Render pass subpass count not set yet");
|
||||
return;
|
||||
}
|
||||
if ((mPropertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
|
||||
HandleError("Render pass attachment count not set yet");
|
||||
return;
|
||||
}
|
||||
if (subpass >= mSubpasses.size()) {
|
||||
HandleError("Subpass index out of bounds");
|
||||
return;
|
||||
}
|
||||
if (attachmentSlot >= mAttachments.size()) {
|
||||
HandleError("Subpass attachment slot out of bounds");
|
||||
return;
|
||||
}
|
||||
if (mSubpasses[subpass].depthStencilAttachmentSet) {
|
||||
HandleError("Subpass depth-stencil attachment already set");
|
||||
return;
|
||||
}
|
||||
|
||||
mSubpasses[subpass].depthStencilAttachmentSet = true;
|
||||
mSubpasses[subpass].depthStencilAttachment = attachmentSlot;
|
||||
}
|
||||
|
||||
} // namespace backend
|
|
@ -1,96 +0,0 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef BACKEND_RENDERPASS_H_
|
||||
#define BACKEND_RENDERPASS_H_
|
||||
|
||||
#include "backend/Builder.h"
|
||||
#include "backend/Forward.h"
|
||||
#include "backend/RefCounted.h"
|
||||
#include "common/Constants.h"
|
||||
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
|
||||
namespace backend {
|
||||
|
||||
class RenderPassBase : public RefCounted {
|
||||
public:
|
||||
RenderPassBase(RenderPassBuilder* builder);
|
||||
|
||||
struct AttachmentInfo {
|
||||
nxt::TextureFormat format;
|
||||
nxt::LoadOp colorLoadOp = nxt::LoadOp::Load;
|
||||
nxt::LoadOp depthLoadOp = nxt::LoadOp::Load;
|
||||
nxt::LoadOp stencilLoadOp = nxt::LoadOp::Load;
|
||||
// The first subpass that this attachment is used in. This is used to determine, for
|
||||
// each subpass, whether each of its attachments is being used for the first time.
|
||||
uint32_t firstSubpass = UINT32_MAX;
|
||||
};
|
||||
|
||||
struct SubpassInfo {
|
||||
// Set of locations which are set
|
||||
std::bitset<kMaxColorAttachments> colorAttachmentsSet;
|
||||
// Mapping from location to attachment slot
|
||||
std::array<uint32_t, kMaxColorAttachments> colorAttachments;
|
||||
bool depthStencilAttachmentSet = false;
|
||||
uint32_t depthStencilAttachment = 0;
|
||||
};
|
||||
|
||||
uint32_t GetAttachmentCount() const;
|
||||
const AttachmentInfo& GetAttachmentInfo(uint32_t attachment) const;
|
||||
uint32_t GetSubpassCount() const;
|
||||
const SubpassInfo& GetSubpassInfo(uint32_t subpass) const;
|
||||
bool IsCompatibleWith(const RenderPassBase* other) const;
|
||||
|
||||
private:
|
||||
std::vector<AttachmentInfo> mAttachments;
|
||||
std::vector<SubpassInfo> mSubpasses;
|
||||
};
|
||||
|
||||
class RenderPassBuilder : public Builder<RenderPassBase> {
|
||||
public:
|
||||
RenderPassBuilder(DeviceBase* device);
|
||||
|
||||
// NXT API
|
||||
RenderPassBase* GetResultImpl() override;
|
||||
void SetAttachmentCount(uint32_t attachmentCount);
|
||||
void AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format);
|
||||
void AttachmentSetColorLoadOp(uint32_t attachmentSlot, nxt::LoadOp op);
|
||||
void AttachmentSetDepthStencilLoadOps(uint32_t attachmentSlot,
|
||||
nxt::LoadOp depthOp,
|
||||
nxt::LoadOp stencilOp);
|
||||
void SetSubpassCount(uint32_t subpassCount);
|
||||
void SubpassSetColorAttachment(uint32_t subpass,
|
||||
uint32_t outputAttachmentLocation,
|
||||
uint32_t attachmentSlot);
|
||||
void SubpassSetDepthStencilAttachment(uint32_t subpass, uint32_t attachmentSlot);
|
||||
|
||||
private:
|
||||
friend class RenderPassBase;
|
||||
|
||||
enum AttachmentProperty { ATTACHMENT_PROPERTY_FORMAT, ATTACHMENT_PROPERTY_COUNT };
|
||||
|
||||
std::vector<std::bitset<ATTACHMENT_PROPERTY_COUNT>> mAttachmentProperties;
|
||||
std::vector<RenderPassBase::AttachmentInfo> mAttachments;
|
||||
std::vector<RenderPassBase::SubpassInfo> mSubpasses;
|
||||
int mPropertiesSet = 0;
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
|
||||
#endif // BACKEND_RENDERPASS_H_
|
|
@ -0,0 +1,180 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "backend/RenderPassInfo.h"
|
||||
|
||||
#include "backend/Device.h"
|
||||
#include "backend/Texture.h"
|
||||
#include "common/Assert.h"
|
||||
#include "common/BitSetIterator.h"
|
||||
|
||||
namespace backend {
|
||||
|
||||
// RenderPassInfo
|
||||
|
||||
RenderPassInfoBase::RenderPassInfoBase(RenderPassInfoBuilder* builder)
|
||||
: mColorAttachmentsSet(builder->mColorAttachmentsSet),
|
||||
mColorAttachments(builder->mColorAttachments),
|
||||
mDepthStencilAttachmentSet(builder->mDepthStencilAttachmentSet),
|
||||
mDepthStencilAttachment(builder->mDepthStencilAttachment),
|
||||
mWidth(builder->mWidth),
|
||||
mHeight(builder->mHeight) {
|
||||
}
|
||||
|
||||
std::bitset<kMaxColorAttachments> RenderPassInfoBase::GetColorAttachmentMask() const {
|
||||
return mColorAttachmentsSet;
|
||||
}
|
||||
|
||||
bool RenderPassInfoBase::HasDepthStencilAttachment() const {
|
||||
return mDepthStencilAttachmentSet;
|
||||
}
|
||||
|
||||
const RenderPassColorAttachmentInfo& RenderPassInfoBase::GetColorAttachment(
|
||||
uint32_t attachment) const {
|
||||
ASSERT(attachment < kMaxColorAttachments);
|
||||
ASSERT(mColorAttachmentsSet[attachment]);
|
||||
|
||||
return mColorAttachments[attachment];
|
||||
}
|
||||
|
||||
RenderPassColorAttachmentInfo& RenderPassInfoBase::GetColorAttachment(uint32_t attachment) {
|
||||
ASSERT(attachment < kMaxColorAttachments);
|
||||
ASSERT(mColorAttachmentsSet[attachment]);
|
||||
|
||||
return mColorAttachments[attachment];
|
||||
}
|
||||
|
||||
const RenderPassDepthStencilAttachmentInfo& RenderPassInfoBase::GetDepthStencilAttachment()
|
||||
const {
|
||||
ASSERT(mDepthStencilAttachmentSet);
|
||||
|
||||
return mDepthStencilAttachment;
|
||||
}
|
||||
|
||||
RenderPassDepthStencilAttachmentInfo& RenderPassInfoBase::GetDepthStencilAttachment() {
|
||||
ASSERT(mDepthStencilAttachmentSet);
|
||||
|
||||
return mDepthStencilAttachment;
|
||||
}
|
||||
|
||||
uint32_t RenderPassInfoBase::GetWidth() const {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
uint32_t RenderPassInfoBase::GetHeight() const {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
// RenderPassInfoBuilder
|
||||
|
||||
RenderPassInfoBuilder::RenderPassInfoBuilder(DeviceBase* device) : Builder(device) {
|
||||
}
|
||||
|
||||
RenderPassInfoBase* RenderPassInfoBuilder::GetResultImpl() {
|
||||
auto CheckOrSetSize = [this](const TextureViewBase* attachment) -> bool {
|
||||
if (this->mWidth == 0) {
|
||||
ASSERT(this->mHeight == 0);
|
||||
|
||||
this->mWidth = attachment->GetTexture()->GetWidth();
|
||||
this->mHeight = attachment->GetTexture()->GetHeight();
|
||||
ASSERT(this->mWidth != 0 && this->mHeight != 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ASSERT(this->mWidth != 0 && this->mHeight != 0);
|
||||
return this->mWidth == attachment->GetTexture()->GetWidth() &&
|
||||
this->mHeight == attachment->GetTexture()->GetHeight();
|
||||
};
|
||||
|
||||
uint32_t attachmentCount = 0;
|
||||
for (uint32_t i : IterateBitSet(mColorAttachmentsSet)) {
|
||||
attachmentCount++;
|
||||
if (!CheckOrSetSize(mColorAttachments[i].view.Get())) {
|
||||
HandleError("Attachment size mismatch");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (mDepthStencilAttachmentSet) {
|
||||
attachmentCount++;
|
||||
if (!CheckOrSetSize(mDepthStencilAttachment.view.Get())) {
|
||||
HandleError("Attachment size mismatch");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (attachmentCount == 0) {
|
||||
HandleError("Should have at least one attachment");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mDevice->CreateRenderPassInfo(this);
|
||||
}
|
||||
|
||||
void RenderPassInfoBuilder::SetColorAttachment(uint32_t attachment,
|
||||
TextureViewBase* textureView,
|
||||
nxt::LoadOp loadOp) {
|
||||
if (attachment >= kMaxColorAttachments) {
|
||||
HandleError("Setting color attachment out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
if (TextureFormatHasDepthOrStencil(textureView->GetTexture()->GetFormat())) {
|
||||
HandleError("Using depth stencil texture as color attachment");
|
||||
return;
|
||||
}
|
||||
|
||||
mColorAttachmentsSet.set(attachment);
|
||||
mColorAttachments[attachment].loadOp = loadOp;
|
||||
mColorAttachments[attachment].view = textureView;
|
||||
}
|
||||
|
||||
void RenderPassInfoBuilder::SetColorAttachmentClearColor(uint32_t attachment,
|
||||
float clearR,
|
||||
float clearG,
|
||||
float clearB,
|
||||
float clearA) {
|
||||
if (attachment >= kMaxColorAttachments) {
|
||||
HandleError("Setting color attachment out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
mColorAttachments[attachment].clearColor[0] = clearR;
|
||||
mColorAttachments[attachment].clearColor[1] = clearG;
|
||||
mColorAttachments[attachment].clearColor[2] = clearB;
|
||||
mColorAttachments[attachment].clearColor[3] = clearA;
|
||||
}
|
||||
|
||||
void RenderPassInfoBuilder::SetDepthStencilAttachment(TextureViewBase* textureView,
|
||||
nxt::LoadOp depthLoadOp,
|
||||
nxt::LoadOp stencilLoadOp) {
|
||||
if (!TextureFormatHasDepthOrStencil(textureView->GetTexture()->GetFormat())) {
|
||||
HandleError("Using color texture as depth stencil attachment");
|
||||
return;
|
||||
}
|
||||
|
||||
mDepthStencilAttachmentSet = true;
|
||||
mDepthStencilAttachment.depthLoadOp = depthLoadOp;
|
||||
mDepthStencilAttachment.stencilLoadOp = stencilLoadOp;
|
||||
mDepthStencilAttachment.view = textureView;
|
||||
}
|
||||
|
||||
void RenderPassInfoBuilder::SetDepthStencilAttachmentClearValue(float clearDepth,
|
||||
uint32_t clearStencil) {
|
||||
mDepthStencilAttachment.clearDepth = clearDepth;
|
||||
mDepthStencilAttachment.clearStencil = clearStencil;
|
||||
}
|
||||
|
||||
} // namespace backend
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef BACKEND_RENDERPASSINFO_H_
|
||||
#define BACKEND_RENDERPASSINFO_H_
|
||||
|
||||
#include "backend/Builder.h"
|
||||
#include "backend/Forward.h"
|
||||
#include "backend/RefCounted.h"
|
||||
#include "common/Constants.h"
|
||||
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <vector>
|
||||
|
||||
namespace backend {
|
||||
|
||||
struct RenderPassColorAttachmentInfo {
|
||||
nxt::LoadOp loadOp;
|
||||
std::array<float, 4> clearColor = {{0.0f, 0.0f, 0.0f, 0.0f}};
|
||||
Ref<TextureViewBase> view;
|
||||
};
|
||||
|
||||
struct RenderPassDepthStencilAttachmentInfo {
|
||||
nxt::LoadOp depthLoadOp;
|
||||
nxt::LoadOp stencilLoadOp;
|
||||
float clearDepth = 1.0f;
|
||||
uint32_t clearStencil = 0;
|
||||
Ref<TextureViewBase> view;
|
||||
};
|
||||
|
||||
// RenderPassInfo contains the list of attachments for a renderpass along with data such as the
|
||||
// load operation and the clear values for the attachments.
|
||||
|
||||
class RenderPassInfoBase : public RefCounted {
|
||||
public:
|
||||
RenderPassInfoBase(RenderPassInfoBuilder* builder);
|
||||
|
||||
std::bitset<kMaxColorAttachments> GetColorAttachmentMask() const;
|
||||
bool HasDepthStencilAttachment() const;
|
||||
|
||||
const RenderPassColorAttachmentInfo& GetColorAttachment(uint32_t attachment) const;
|
||||
RenderPassColorAttachmentInfo& GetColorAttachment(uint32_t attachment);
|
||||
const RenderPassDepthStencilAttachmentInfo& GetDepthStencilAttachment() const;
|
||||
RenderPassDepthStencilAttachmentInfo& GetDepthStencilAttachment();
|
||||
|
||||
// All attachments of the render pass have the same size, these return that size.
|
||||
uint32_t GetWidth() const;
|
||||
uint32_t GetHeight() const;
|
||||
|
||||
private:
|
||||
std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
|
||||
std::array<RenderPassColorAttachmentInfo, kMaxColorAttachments> mColorAttachments;
|
||||
|
||||
bool mDepthStencilAttachmentSet;
|
||||
RenderPassDepthStencilAttachmentInfo mDepthStencilAttachment;
|
||||
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
};
|
||||
|
||||
class RenderPassInfoBuilder : public Builder<RenderPassInfoBase> {
|
||||
public:
|
||||
RenderPassInfoBuilder(DeviceBase* device);
|
||||
|
||||
// NXT API
|
||||
RenderPassInfoBase* GetResultImpl() override;
|
||||
void SetColorAttachment(uint32_t attachment,
|
||||
TextureViewBase* textureView,
|
||||
nxt::LoadOp loadOp);
|
||||
void SetColorAttachmentClearColor(uint32_t attachment,
|
||||
float clearR,
|
||||
float clearG,
|
||||
float clearB,
|
||||
float clearA);
|
||||
void SetDepthStencilAttachment(TextureViewBase* textureView,
|
||||
nxt::LoadOp depthLoadOp,
|
||||
nxt::LoadOp stencilLoadOp);
|
||||
void SetDepthStencilAttachmentClearValue(float clearDepth, uint32_t clearStencil);
|
||||
|
||||
private:
|
||||
friend class RenderPassInfoBase;
|
||||
|
||||
std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
|
||||
std::array<RenderPassColorAttachmentInfo, kMaxColorAttachments> mColorAttachments;
|
||||
|
||||
bool mDepthStencilAttachmentSet = false;
|
||||
RenderPassDepthStencilAttachmentInfo mDepthStencilAttachment;
|
||||
|
||||
uint32_t mWidth = 0;
|
||||
uint32_t mHeight = 0;
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
|
||||
#endif // BACKEND_RENDERPASS_H_
|
|
@ -18,7 +18,8 @@
|
|||
#include "backend/DepthStencilState.h"
|
||||
#include "backend/Device.h"
|
||||
#include "backend/InputState.h"
|
||||
#include "backend/RenderPass.h"
|
||||
#include "backend/RenderPassInfo.h"
|
||||
#include "backend/Texture.h"
|
||||
#include "common/BitSetIterator.h"
|
||||
|
||||
namespace backend {
|
||||
|
@ -32,8 +33,10 @@ namespace backend {
|
|||
mInputState(std::move(builder->mInputState)),
|
||||
mPrimitiveTopology(builder->mPrimitiveTopology),
|
||||
mBlendStates(builder->mBlendStates),
|
||||
mRenderPass(std::move(builder->mRenderPass)),
|
||||
mSubpass(builder->mSubpass) {
|
||||
mColorAttachmentsSet(builder->mColorAttachmentsSet),
|
||||
mColorAttachmentFormats(builder->mColorAttachmentFormats),
|
||||
mDepthStencilFormatSet(builder->mDepthStencilFormatSet),
|
||||
mDepthStencilFormat(builder->mDepthStencilFormat) {
|
||||
if (GetStageMask() != (nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
|
||||
builder->HandleError("Render pipeline should have exactly a vertex and fragment stage");
|
||||
return;
|
||||
|
@ -47,6 +50,19 @@ namespace backend {
|
|||
builder->HandleError("Pipeline vertex stage uses inputs not in the input state");
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(cwallez@chromium.org): Check against the shader module that the correct color
|
||||
// attachment are set?
|
||||
|
||||
size_t attachmentCount = mColorAttachmentsSet.count();
|
||||
if (mDepthStencilFormatSet) {
|
||||
attachmentCount++;
|
||||
}
|
||||
|
||||
if (attachmentCount == 0) {
|
||||
builder->HandleError("Should have at least one attachment");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BlendStateBase* RenderPipelineBase::GetBlendState(uint32_t attachmentSlot) {
|
||||
|
@ -70,12 +86,49 @@ namespace backend {
|
|||
return mPrimitiveTopology;
|
||||
}
|
||||
|
||||
RenderPassBase* RenderPipelineBase::GetRenderPass() {
|
||||
return mRenderPass.Get();
|
||||
std::bitset<kMaxColorAttachments> RenderPipelineBase::GetColorAttachmentsMask() const {
|
||||
return mColorAttachmentsSet;
|
||||
}
|
||||
|
||||
uint32_t RenderPipelineBase::GetSubPass() {
|
||||
return mSubpass;
|
||||
bool RenderPipelineBase::HasDepthStencilAttachment() const {
|
||||
return mDepthStencilFormatSet;
|
||||
}
|
||||
|
||||
nxt::TextureFormat RenderPipelineBase::GetColorAttachmentFormat(uint32_t attachment) const {
|
||||
return mColorAttachmentFormats[attachment];
|
||||
}
|
||||
|
||||
nxt::TextureFormat RenderPipelineBase::GetDepthStencilFormat() const {
|
||||
return mDepthStencilFormat;
|
||||
}
|
||||
|
||||
bool RenderPipelineBase::IsCompatibleWith(const RenderPassInfoBase* renderPass) const {
|
||||
// TODO(cwallez@chromium.org): This is called on every SetPipeline command. Optimize it for
|
||||
// example by caching some "attachment compatibility" object that would make the
|
||||
// compatibility check a single pointer comparison.
|
||||
|
||||
if (renderPass->GetColorAttachmentMask() != mColorAttachmentsSet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i : IterateBitSet(mColorAttachmentsSet)) {
|
||||
if (renderPass->GetColorAttachment(i).view->GetTexture()->GetFormat() !=
|
||||
mColorAttachmentFormats[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (renderPass->HasDepthStencilAttachment() != mDepthStencilFormatSet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mDepthStencilFormatSet &&
|
||||
(renderPass->GetDepthStencilAttachment().view->GetTexture()->GetFormat() !=
|
||||
mDepthStencilFormat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// RenderPipelineBuilder
|
||||
|
@ -101,21 +154,15 @@ namespace backend {
|
|||
mDepthStencilState->Release();
|
||||
builder->Release();
|
||||
}
|
||||
if (!mRenderPass) {
|
||||
HandleError("Pipeline render pass not set");
|
||||
return nullptr;
|
||||
}
|
||||
const auto& subpassInfo = mRenderPass->GetSubpassInfo(mSubpass);
|
||||
if ((mBlendStatesSet | subpassInfo.colorAttachmentsSet) !=
|
||||
subpassInfo.colorAttachmentsSet) {
|
||||
|
||||
if ((mBlendStatesSet | mColorAttachmentsSet) != mColorAttachmentsSet) {
|
||||
HandleError("Blend state set on unset color attachment");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Assign all color attachments without a blend state the default state
|
||||
// TODO(enga@google.com): Put the default objects in the device
|
||||
for (uint32_t attachmentSlot :
|
||||
IterateBitSet(subpassInfo.colorAttachmentsSet & ~mBlendStatesSet)) {
|
||||
for (uint32_t attachmentSlot : IterateBitSet(mColorAttachmentsSet & ~mBlendStatesSet)) {
|
||||
mBlendStates[attachmentSlot] = mDevice->CreateBlendStateBuilder()->GetResult();
|
||||
// Remove the external ref objects are created with
|
||||
mBlendStates[attachmentSlot]->Release();
|
||||
|
@ -124,9 +171,20 @@ namespace backend {
|
|||
return mDevice->CreateRenderPipeline(this);
|
||||
}
|
||||
|
||||
void RenderPipelineBuilder::SetColorAttachmentFormat(uint32_t attachmentSlot,
|
||||
nxt::TextureFormat format) {
|
||||
if (attachmentSlot >= kMaxColorAttachments) {
|
||||
HandleError("Attachment index out of bounds");
|
||||
return;
|
||||
}
|
||||
|
||||
mColorAttachmentsSet.set(attachmentSlot);
|
||||
mColorAttachmentFormats[attachmentSlot] = format;
|
||||
}
|
||||
|
||||
void RenderPipelineBuilder::SetColorAttachmentBlendState(uint32_t attachmentSlot,
|
||||
BlendStateBase* blendState) {
|
||||
if (attachmentSlot > mBlendStates.size()) {
|
||||
if (attachmentSlot >= kMaxColorAttachments) {
|
||||
HandleError("Attachment index out of bounds");
|
||||
return;
|
||||
}
|
||||
|
@ -143,6 +201,11 @@ namespace backend {
|
|||
mDepthStencilState = depthStencilState;
|
||||
}
|
||||
|
||||
void RenderPipelineBuilder::SetDepthStencilAttachmentFormat(nxt::TextureFormat format) {
|
||||
mDepthStencilFormatSet = true;
|
||||
mDepthStencilFormat = format;
|
||||
}
|
||||
|
||||
void RenderPipelineBuilder::SetIndexFormat(nxt::IndexFormat format) {
|
||||
mIndexFormat = format;
|
||||
}
|
||||
|
@ -155,9 +218,4 @@ namespace backend {
|
|||
mPrimitiveTopology = primitiveTopology;
|
||||
}
|
||||
|
||||
void RenderPipelineBuilder::SetSubpass(RenderPassBase* renderPass, uint32_t subpass) {
|
||||
mRenderPass = renderPass;
|
||||
mSubpass = subpass;
|
||||
}
|
||||
|
||||
} // namespace backend
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include "backend/DepthStencilState.h"
|
||||
#include "backend/InputState.h"
|
||||
#include "backend/Pipeline.h"
|
||||
#include "backend/RenderPass.h"
|
||||
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
||||
|
@ -37,8 +36,15 @@ namespace backend {
|
|||
nxt::IndexFormat GetIndexFormat() const;
|
||||
InputStateBase* GetInputState();
|
||||
nxt::PrimitiveTopology GetPrimitiveTopology() const;
|
||||
RenderPassBase* GetRenderPass();
|
||||
uint32_t GetSubPass();
|
||||
|
||||
std::bitset<kMaxColorAttachments> GetColorAttachmentsMask() const;
|
||||
bool HasDepthStencilAttachment() const;
|
||||
nxt::TextureFormat GetColorAttachmentFormat(uint32_t attachment) const;
|
||||
nxt::TextureFormat GetDepthStencilFormat() const;
|
||||
|
||||
// A pipeline can be used in a render pass if its attachment info matches the actual
|
||||
// attachments in the render pass. This returns whether it is the case.
|
||||
bool IsCompatibleWith(const RenderPassInfoBase* renderPass) const;
|
||||
|
||||
private:
|
||||
Ref<DepthStencilStateBase> mDepthStencilState;
|
||||
|
@ -46,8 +52,11 @@ namespace backend {
|
|||
Ref<InputStateBase> mInputState;
|
||||
nxt::PrimitiveTopology mPrimitiveTopology;
|
||||
std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates;
|
||||
Ref<RenderPassBase> mRenderPass;
|
||||
uint32_t mSubpass;
|
||||
|
||||
std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
|
||||
std::array<nxt::TextureFormat, kMaxColorAttachments> mColorAttachmentFormats;
|
||||
bool mDepthStencilFormatSet = false;
|
||||
nxt::TextureFormat mDepthStencilFormat;
|
||||
};
|
||||
|
||||
class RenderPipelineBuilder : public Builder<RenderPipelineBase>, public PipelineBuilder {
|
||||
|
@ -55,12 +64,13 @@ namespace backend {
|
|||
RenderPipelineBuilder(DeviceBase* device);
|
||||
|
||||
// NXT API
|
||||
void SetColorAttachmentFormat(uint32_t attachmentSlot, nxt::TextureFormat format);
|
||||
void SetColorAttachmentBlendState(uint32_t attachmentSlot, BlendStateBase* blendState);
|
||||
void SetDepthStencilAttachmentFormat(nxt::TextureFormat format);
|
||||
void SetDepthStencilState(DepthStencilStateBase* depthStencilState);
|
||||
void SetPrimitiveTopology(nxt::PrimitiveTopology primitiveTopology);
|
||||
void SetIndexFormat(nxt::IndexFormat format);
|
||||
void SetInputState(InputStateBase* inputState);
|
||||
void SetSubpass(RenderPassBase* renderPass, uint32_t subpass);
|
||||
|
||||
private:
|
||||
friend class RenderPipelineBase;
|
||||
|
@ -75,8 +85,10 @@ namespace backend {
|
|||
nxt::IndexFormat mIndexFormat = nxt::IndexFormat::Uint32;
|
||||
std::bitset<kMaxColorAttachments> mBlendStatesSet;
|
||||
std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates;
|
||||
Ref<RenderPassBase> mRenderPass;
|
||||
uint32_t mSubpass;
|
||||
std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
|
||||
std::array<nxt::TextureFormat, kMaxColorAttachments> mColorAttachmentFormats;
|
||||
bool mDepthStencilFormatSet = false;
|
||||
nxt::TextureFormat mDepthStencilFormat;
|
||||
};
|
||||
|
||||
} // namespace backend
|
||||
|
|
|
@ -267,6 +267,10 @@ namespace backend {
|
|||
TextureViewBase::TextureViewBase(TextureViewBuilder* builder) : mTexture(builder->mTexture) {
|
||||
}
|
||||
|
||||
const TextureBase* TextureViewBase::GetTexture() const {
|
||||
return mTexture.Get();
|
||||
}
|
||||
|
||||
TextureBase* TextureViewBase::GetTexture() {
|
||||
return mTexture.Get();
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ namespace backend {
|
|||
public:
|
||||
TextureViewBase(TextureViewBuilder* builder);
|
||||
|
||||
const TextureBase* GetTexture() const;
|
||||
TextureBase* GetTexture();
|
||||
|
||||
private:
|
||||
|
|
|
@ -68,11 +68,6 @@ namespace backend {
|
|||
using BackendType = typename BackendTraits::DeviceType;
|
||||
};
|
||||
|
||||
template <typename BackendTraits>
|
||||
struct ToBackendTraits<FramebufferBase, BackendTraits> {
|
||||
using BackendType = typename BackendTraits::FramebufferType;
|
||||
};
|
||||
|
||||
template <typename BackendTraits>
|
||||
struct ToBackendTraits<InputStateBase, BackendTraits> {
|
||||
using BackendType = typename BackendTraits::InputStateType;
|
||||
|
@ -89,8 +84,8 @@ namespace backend {
|
|||
};
|
||||
|
||||
template <typename BackendTraits>
|
||||
struct ToBackendTraits<RenderPassBase, BackendTraits> {
|
||||
using BackendType = typename BackendTraits::RenderPassType;
|
||||
struct ToBackendTraits<RenderPassInfoBase, BackendTraits> {
|
||||
using BackendType = typename BackendTraits::RenderPassInfoType;
|
||||
};
|
||||
|
||||
template <typename BackendTraits>
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
#include "backend/d3d12/ComputePipelineD3D12.h"
|
||||
#include "backend/d3d12/D3D12Backend.h"
|
||||
#include "backend/d3d12/DescriptorHeapAllocator.h"
|
||||
#include "backend/d3d12/FramebufferD3D12.h"
|
||||
#include "backend/d3d12/InputStateD3D12.h"
|
||||
#include "backend/d3d12/PipelineLayoutD3D12.h"
|
||||
#include "backend/d3d12/RenderPassInfoD3D12.h"
|
||||
#include "backend/d3d12/RenderPipelineD3D12.h"
|
||||
#include "backend/d3d12/ResourceAllocator.h"
|
||||
#include "backend/d3d12/SamplerD3D12.h"
|
||||
|
@ -255,10 +255,6 @@ namespace backend { namespace d3d12 {
|
|||
RenderPipeline* lastRenderPipeline = nullptr;
|
||||
PipelineLayout* lastLayout = nullptr;
|
||||
|
||||
RenderPass* currentRenderPass = nullptr;
|
||||
Framebuffer* currentFramebuffer = nullptr;
|
||||
uint32_t currentSubpass = 0;
|
||||
|
||||
while (mCommands.NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::BeginComputePass: {
|
||||
|
@ -269,26 +265,10 @@ namespace backend { namespace d3d12 {
|
|||
case Command::BeginRenderPass: {
|
||||
BeginRenderPassCmd* beginRenderPassCmd =
|
||||
mCommands.NextCommand<BeginRenderPassCmd>();
|
||||
currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
|
||||
currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
|
||||
currentSubpass = 0;
|
||||
RenderPassInfo* info = ToBackend(beginRenderPassCmd->info.Get());
|
||||
|
||||
uint32_t width = currentFramebuffer->GetWidth();
|
||||
uint32_t height = currentFramebuffer->GetHeight();
|
||||
D3D12_VIEWPORT viewport = {
|
||||
0.f, 0.f, static_cast<float>(width), static_cast<float>(height), 0.f, 1.f};
|
||||
D3D12_RECT scissorRect = {0, 0, static_cast<long>(width),
|
||||
static_cast<long>(height)};
|
||||
commandList->RSSetViewports(1, &viewport);
|
||||
commandList->RSSetScissorRects(1, &scissorRect);
|
||||
} break;
|
||||
|
||||
case Command::BeginRenderSubpass: {
|
||||
mCommands.NextCommand<BeginRenderSubpassCmd>();
|
||||
const auto& subpass = currentRenderPass->GetSubpassInfo(currentSubpass);
|
||||
|
||||
Framebuffer::OMSetRenderTargetArgs args =
|
||||
currentFramebuffer->GetSubpassOMSetRenderTargetArgs(currentSubpass);
|
||||
RenderPassInfo::OMSetRenderTargetArgs args =
|
||||
info->GetSubpassOMSetRenderTargetArgs();
|
||||
if (args.dsv.ptr) {
|
||||
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE,
|
||||
&args.dsv);
|
||||
|
@ -297,69 +277,77 @@ namespace backend { namespace d3d12 {
|
|||
nullptr);
|
||||
}
|
||||
|
||||
// Clear framebuffer attachments as needed
|
||||
// Clear framebuffer attachments as needed and transition to render target
|
||||
|
||||
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
|
||||
uint32_t attachmentSlot = subpass.colorAttachments[location];
|
||||
const auto& attachmentInfo =
|
||||
currentRenderPass->GetAttachmentInfo(attachmentSlot);
|
||||
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
|
||||
auto& attachmentInfo = info->GetColorAttachment(i);
|
||||
Texture* texture = ToBackend(attachmentInfo.view->GetTexture());
|
||||
|
||||
Texture* texture = ToBackend(
|
||||
currentFramebuffer->GetTextureView(attachmentSlot)->GetTexture());
|
||||
constexpr auto usage = nxt::TextureUsageBit::OutputAttachment;
|
||||
// It's already validated that this texture is either frozen to the correct
|
||||
// usage, or not frozen.
|
||||
if (!texture->IsFrozen()) {
|
||||
texture->TransitionUsageImpl(texture->GetUsage(), usage);
|
||||
texture->UpdateUsageInternal(usage);
|
||||
texture->TransitionUsageImpl(texture->GetUsage(),
|
||||
nxt::TextureUsageBit::OutputAttachment);
|
||||
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
|
||||
}
|
||||
|
||||
// Only perform load op on first use
|
||||
if (attachmentInfo.firstSubpass == currentSubpass) {
|
||||
// Load op - color
|
||||
if (attachmentInfo.colorLoadOp == nxt::LoadOp::Clear) {
|
||||
auto handle = currentFramebuffer->GetRTVDescriptor(attachmentSlot);
|
||||
const auto& clear =
|
||||
currentFramebuffer->GetClearColor(attachmentSlot);
|
||||
commandList->ClearRenderTargetView(handle, clear.color, 0, nullptr);
|
||||
}
|
||||
// Load op - color
|
||||
if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE handle = info->GetRTVDescriptor(i);
|
||||
commandList->ClearRenderTargetView(
|
||||
handle, attachmentInfo.clearColor.data(), 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (subpass.depthStencilAttachmentSet) {
|
||||
uint32_t attachmentSlot = subpass.depthStencilAttachment;
|
||||
const auto& attachmentInfo =
|
||||
currentRenderPass->GetAttachmentInfo(attachmentSlot);
|
||||
if (info->HasDepthStencilAttachment()) {
|
||||
auto& attachmentInfo = info->GetDepthStencilAttachment();
|
||||
Texture* texture = ToBackend(attachmentInfo.view->GetTexture());
|
||||
|
||||
// Only perform load op on first use
|
||||
if (attachmentInfo.firstSubpass == currentSubpass) {
|
||||
// Load op - depth/stencil
|
||||
bool doDepthClear = TextureFormatHasDepth(attachmentInfo.format) &&
|
||||
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
|
||||
bool doStencilClear =
|
||||
TextureFormatHasStencil(attachmentInfo.format) &&
|
||||
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
|
||||
// It's already validated that this texture is either frozen to the correct
|
||||
// usage, or not frozen.
|
||||
if (!texture->IsFrozen()) {
|
||||
texture->TransitionUsageImpl(texture->GetUsage(),
|
||||
nxt::TextureUsageBit::OutputAttachment);
|
||||
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
|
||||
}
|
||||
|
||||
D3D12_CLEAR_FLAGS clearFlags = {};
|
||||
if (doDepthClear) {
|
||||
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
|
||||
}
|
||||
if (doStencilClear) {
|
||||
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
|
||||
}
|
||||
if (clearFlags) {
|
||||
auto handle = currentFramebuffer->GetDSVDescriptor(attachmentSlot);
|
||||
const auto& clear =
|
||||
currentFramebuffer->GetClearDepthStencil(attachmentSlot);
|
||||
// TODO(kainino@chromium.org): investigate: should the NXT clear
|
||||
// stencil type be uint8_t?
|
||||
uint8_t clearStencil = static_cast<uint8_t>(clear.stencil);
|
||||
commandList->ClearDepthStencilView(handle, clearFlags, clear.depth,
|
||||
clearStencil, 0, nullptr);
|
||||
}
|
||||
// Load op - depth/stencil
|
||||
bool doDepthClear = TextureFormatHasDepth(texture->GetFormat()) &&
|
||||
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
|
||||
bool doStencilClear = TextureFormatHasStencil(texture->GetFormat()) &&
|
||||
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
|
||||
|
||||
D3D12_CLEAR_FLAGS clearFlags = {};
|
||||
if (doDepthClear) {
|
||||
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
|
||||
}
|
||||
if (doStencilClear) {
|
||||
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
|
||||
}
|
||||
|
||||
if (clearFlags) {
|
||||
auto handle = info->GetDSVDescriptor();
|
||||
// TODO(kainino@chromium.org): investigate: should the NXT clear
|
||||
// stencil type be uint8_t?
|
||||
uint8_t clearStencil =
|
||||
static_cast<uint8_t>(attachmentInfo.clearStencil);
|
||||
commandList->ClearDepthStencilView(handle, clearFlags,
|
||||
attachmentInfo.clearDepth,
|
||||
clearStencil, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the default render pass dynamic state
|
||||
|
||||
uint32_t width = info->GetWidth();
|
||||
uint32_t height = info->GetHeight();
|
||||
D3D12_VIEWPORT viewport = {
|
||||
0.f, 0.f, static_cast<float>(width), static_cast<float>(height), 0.f, 1.f};
|
||||
D3D12_RECT scissorRect = {0, 0, static_cast<long>(width),
|
||||
static_cast<long>(height)};
|
||||
commandList->RSSetViewports(1, &viewport);
|
||||
commandList->RSSetScissorRects(1, &scissorRect);
|
||||
|
||||
static constexpr std::array<float, 4> defaultBlendFactor = {0, 0, 0, 0};
|
||||
commandList->OMSetBlendFactor(&defaultBlendFactor[0]);
|
||||
} break;
|
||||
|
@ -485,11 +473,6 @@ namespace backend { namespace d3d12 {
|
|||
mCommands.NextCommand<EndRenderPassCmd>();
|
||||
} break;
|
||||
|
||||
case Command::EndRenderSubpass: {
|
||||
mCommands.NextCommand<EndRenderSubpassCmd>();
|
||||
currentSubpass += 1;
|
||||
} break;
|
||||
|
||||
case Command::SetComputePipeline: {
|
||||
SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>();
|
||||
ComputePipeline* pipeline = ToBackend(cmd->pipeline).Get();
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
#include "backend/d3d12/ComputePipelineD3D12.h"
|
||||
#include "backend/d3d12/DepthStencilStateD3D12.h"
|
||||
#include "backend/d3d12/DescriptorHeapAllocator.h"
|
||||
#include "backend/d3d12/FramebufferD3D12.h"
|
||||
#include "backend/d3d12/InputStateD3D12.h"
|
||||
#include "backend/d3d12/NativeSwapChainImplD3D12.h"
|
||||
#include "backend/d3d12/PipelineLayoutD3D12.h"
|
||||
#include "backend/d3d12/QueueD3D12.h"
|
||||
#include "backend/d3d12/RenderPassInfoD3D12.h"
|
||||
#include "backend/d3d12/RenderPipelineD3D12.h"
|
||||
#include "backend/d3d12/ResourceAllocator.h"
|
||||
#include "backend/d3d12/ResourceUploader.h"
|
||||
|
@ -282,9 +282,6 @@ namespace backend { namespace d3d12 {
|
|||
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
|
||||
return new DepthStencilState(this, builder);
|
||||
}
|
||||
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
|
||||
return new Framebuffer(this, builder);
|
||||
}
|
||||
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
|
||||
return new InputState(this, builder);
|
||||
}
|
||||
|
@ -294,8 +291,8 @@ namespace backend { namespace d3d12 {
|
|||
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
|
||||
return new Queue(this, builder);
|
||||
}
|
||||
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
|
||||
return new RenderPass(this, builder);
|
||||
RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
|
||||
return new RenderPassInfo(this, builder);
|
||||
}
|
||||
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
|
||||
return new RenderPipeline(builder);
|
||||
|
@ -316,10 +313,4 @@ namespace backend { namespace d3d12 {
|
|||
return new TextureView(builder);
|
||||
}
|
||||
|
||||
// RenderPass
|
||||
|
||||
RenderPass::RenderPass(Device* device, RenderPassBuilder* builder)
|
||||
: RenderPassBase(builder), mDevice(device) {
|
||||
}
|
||||
|
||||
}} // namespace backend::d3d12
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
#include "backend/DepthStencilState.h"
|
||||
#include "backend/Device.h"
|
||||
#include "backend/RenderPass.h"
|
||||
#include "backend/ToBackend.h"
|
||||
#include "backend/d3d12/d3d12_platform.h"
|
||||
#include "common/SerialQueue.h"
|
||||
|
@ -35,11 +34,10 @@ namespace backend { namespace d3d12 {
|
|||
class ComputePipeline;
|
||||
class DepthStencilState;
|
||||
class Device;
|
||||
class Framebuffer;
|
||||
class InputState;
|
||||
class PipelineLayout;
|
||||
class Queue;
|
||||
class RenderPass;
|
||||
class RenderPassInfo;
|
||||
class RenderPipeline;
|
||||
class Sampler;
|
||||
class ShaderModule;
|
||||
|
@ -63,11 +61,10 @@ namespace backend { namespace d3d12 {
|
|||
using ComputePipelineType = ComputePipeline;
|
||||
using DepthStencilStateType = DepthStencilState;
|
||||
using DeviceType = Device;
|
||||
using FramebufferType = Framebuffer;
|
||||
using InputStateType = InputState;
|
||||
using PipelineLayoutType = PipelineLayout;
|
||||
using QueueType = Queue;
|
||||
using RenderPassType = RenderPass;
|
||||
using RenderPassInfoType = RenderPassInfo;
|
||||
using RenderPipelineType = RenderPipeline;
|
||||
using SamplerType = Sampler;
|
||||
using ShaderModuleType = ShaderModule;
|
||||
|
@ -97,11 +94,10 @@ namespace backend { namespace d3d12 {
|
|||
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
|
||||
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
|
||||
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
|
||||
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
|
||||
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
|
||||
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
|
||||
QueueBase* CreateQueue(QueueBuilder* builder) override;
|
||||
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
|
||||
RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
|
||||
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
||||
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
|
||||
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
|
||||
|
@ -155,14 +151,6 @@ namespace backend { namespace d3d12 {
|
|||
SerialQueue<ComPtr<IUnknown>> mUsedComObjectRefs;
|
||||
};
|
||||
|
||||
class RenderPass : public RenderPassBase {
|
||||
public:
|
||||
RenderPass(Device* device, RenderPassBuilder* builder);
|
||||
|
||||
private:
|
||||
Device* mDevice;
|
||||
};
|
||||
|
||||
}} // namespace backend::d3d12
|
||||
|
||||
#endif // BACKEND_D3D12_D3D12BACKEND_H_
|
||||
|
|
|
@ -1,95 +0,0 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "backend/d3d12/FramebufferD3D12.h"
|
||||
|
||||
#include "backend/d3d12/D3D12Backend.h"
|
||||
#include "backend/d3d12/TextureD3D12.h"
|
||||
#include "common/BitSetIterator.h"
|
||||
|
||||
namespace backend { namespace d3d12 {
|
||||
|
||||
Framebuffer::Framebuffer(Device* device, FramebufferBuilder* builder)
|
||||
: FramebufferBase(builder), mDevice(device) {
|
||||
RenderPass* renderPass = ToBackend(GetRenderPass());
|
||||
|
||||
uint32_t rtvCount = 0, dsvCount = 0;
|
||||
mAttachmentHeapIndices.resize(renderPass->GetAttachmentCount());
|
||||
for (uint32_t attachment = 0; attachment < renderPass->GetAttachmentCount(); ++attachment) {
|
||||
auto* textureView = GetTextureView(attachment);
|
||||
auto format = textureView->GetTexture()->GetFormat();
|
||||
if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) {
|
||||
mAttachmentHeapIndices[attachment] = dsvCount++;
|
||||
} else {
|
||||
mAttachmentHeapIndices[attachment] = rtvCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (rtvCount) {
|
||||
mRtvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_RTV, rtvCount);
|
||||
}
|
||||
if (dsvCount) {
|
||||
mDsvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_DSV, dsvCount);
|
||||
}
|
||||
|
||||
for (uint32_t attachment = 0; attachment < renderPass->GetAttachmentCount(); ++attachment) {
|
||||
uint32_t heapIndex = mAttachmentHeapIndices[attachment];
|
||||
auto* textureView = GetTextureView(attachment);
|
||||
|
||||
ComPtr<ID3D12Resource> texture =
|
||||
ToBackend(textureView->GetTexture())->GetD3D12Resource();
|
||||
auto format = textureView->GetTexture()->GetFormat();
|
||||
if (TextureFormatHasDepth(format) || TextureFormatHasStencil(format)) {
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = mDsvHeap.GetCPUHandle(heapIndex);
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = ToBackend(textureView)->GetDSVDescriptor();
|
||||
device->GetD3D12Device()->CreateDepthStencilView(texture.Get(), &dsvDesc,
|
||||
dsvHandle);
|
||||
} else {
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = mRtvHeap.GetCPUHandle(heapIndex);
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = ToBackend(textureView)->GetRTVDescriptor();
|
||||
device->GetD3D12Device()->CreateRenderTargetView(texture.Get(), &rtvDesc,
|
||||
rtvHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Framebuffer::OMSetRenderTargetArgs Framebuffer::GetSubpassOMSetRenderTargetArgs(
|
||||
uint32_t subpassIndex) {
|
||||
const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(subpassIndex);
|
||||
OMSetRenderTargetArgs args = {};
|
||||
|
||||
for (uint32_t location : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
||||
uint32_t slot = subpassInfo.colorAttachments[location];
|
||||
args.RTVs[args.numRTVs] = GetRTVDescriptor(slot);
|
||||
args.numRTVs++;
|
||||
}
|
||||
if (subpassInfo.depthStencilAttachmentSet) {
|
||||
uint32_t slot = subpassInfo.depthStencilAttachment;
|
||||
args.dsv = GetDSVDescriptor(slot);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE Framebuffer::GetRTVDescriptor(uint32_t attachmentSlot) {
|
||||
return mRtvHeap.GetCPUHandle(mAttachmentHeapIndices[attachmentSlot]);
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE Framebuffer::GetDSVDescriptor(uint32_t attachmentSlot) {
|
||||
return mDsvHeap.GetCPUHandle(mAttachmentHeapIndices[attachmentSlot]);
|
||||
}
|
||||
|
||||
}} // namespace backend::d3d12
|
|
@ -20,10 +20,10 @@
|
|||
#include "backend/d3d12/ComputePipelineD3D12.h"
|
||||
#include "backend/d3d12/D3D12Backend.h"
|
||||
#include "backend/d3d12/DepthStencilStateD3D12.h"
|
||||
#include "backend/d3d12/FramebufferD3D12.h"
|
||||
#include "backend/d3d12/InputStateD3D12.h"
|
||||
#include "backend/d3d12/PipelineLayoutD3D12.h"
|
||||
#include "backend/d3d12/QueueD3D12.h"
|
||||
#include "backend/d3d12/RenderPassInfoD3D12.h"
|
||||
#include "backend/d3d12/RenderPipelineD3D12.h"
|
||||
#include "backend/d3d12/SamplerD3D12.h"
|
||||
#include "backend/d3d12/ShaderModuleD3D12.h"
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "backend/d3d12/RenderPassInfoD3D12.h"
|
||||
|
||||
#include "backend/d3d12/D3D12Backend.h"
|
||||
#include "backend/d3d12/TextureD3D12.h"
|
||||
#include "common/BitSetIterator.h"
|
||||
|
||||
namespace backend { namespace d3d12 {
|
||||
|
||||
RenderPassInfo::RenderPassInfo(Device* device, RenderPassInfoBuilder* builder)
|
||||
: RenderPassInfoBase(builder), mDevice(device) {
|
||||
// Get and fill an RTV heap with the color attachments
|
||||
uint32_t colorAttachmentCount = static_cast<uint32_t>(GetColorAttachmentMask().count());
|
||||
if (colorAttachmentCount != 0) {
|
||||
mRtvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_RTV, colorAttachmentCount);
|
||||
|
||||
for (uint32_t i : IterateBitSet(GetColorAttachmentMask())) {
|
||||
TextureView* view = ToBackend(GetColorAttachment(i).view.Get());
|
||||
ComPtr<ID3D12Resource> resource = ToBackend(view->GetTexture())->GetD3D12Resource();
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = mRtvHeap.GetCPUHandle(i);
|
||||
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = view->GetRTVDescriptor();
|
||||
device->GetD3D12Device()->CreateRenderTargetView(resource.Get(), &rtvDesc,
|
||||
rtvHandle);
|
||||
}
|
||||
}
|
||||
|
||||
// Get and fill a DSV heap with the depth stencil attachment
|
||||
if (HasDepthStencilAttachment()) {
|
||||
mDsvHeap = device->GetDescriptorHeapAllocator()->AllocateCPUHeap(
|
||||
D3D12_DESCRIPTOR_HEAP_TYPE_DSV, 1);
|
||||
|
||||
TextureView* view = ToBackend(GetDepthStencilAttachment().view.Get());
|
||||
ComPtr<ID3D12Resource> resource = ToBackend(view->GetTexture())->GetD3D12Resource();
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = mDsvHeap.GetCPUHandle(0);
|
||||
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = view->GetDSVDescriptor();
|
||||
device->GetD3D12Device()->CreateDepthStencilView(resource.Get(), &dsvDesc, dsvHandle);
|
||||
}
|
||||
}
|
||||
|
||||
RenderPassInfo::OMSetRenderTargetArgs RenderPassInfo::GetSubpassOMSetRenderTargetArgs() {
|
||||
OMSetRenderTargetArgs args = {};
|
||||
|
||||
size_t rtvIndex = 0;
|
||||
for (uint32_t i : IterateBitSet(GetColorAttachmentMask())) {
|
||||
args.RTVs[rtvIndex] = GetRTVDescriptor(i);
|
||||
rtvIndex++;
|
||||
}
|
||||
args.numRTVs = rtvIndex;
|
||||
|
||||
if (HasDepthStencilAttachment()) {
|
||||
args.dsv = GetDSVDescriptor();
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE RenderPassInfo::GetRTVDescriptor(uint32_t attachmentSlot) {
|
||||
return mRtvHeap.GetCPUHandle(attachmentSlot);
|
||||
}
|
||||
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE RenderPassInfo::GetDSVDescriptor() {
|
||||
return mDsvHeap.GetCPUHandle(0);
|
||||
}
|
||||
|
||||
}} // namespace backend::d3d12
|
|
@ -12,10 +12,10 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef BACKEND_D3D12_FRAMEBUFFERD3D12_H_
|
||||
#define BACKEND_D3D12_FRAMEBUFFERD3D12_H_
|
||||
#ifndef BACKEND_D3D12_RENDERPASSINFOD3D12_H_
|
||||
#define BACKEND_D3D12_RENDERPASSINFOD3D12_H_
|
||||
|
||||
#include "backend/Framebuffer.h"
|
||||
#include "backend/RenderPassInfo.h"
|
||||
|
||||
#include "backend/d3d12/DescriptorHeapAllocator.h"
|
||||
#include "backend/d3d12/d3d12_platform.h"
|
||||
|
@ -28,7 +28,7 @@ namespace backend { namespace d3d12 {
|
|||
|
||||
class Device;
|
||||
|
||||
class Framebuffer : public FramebufferBase {
|
||||
class RenderPassInfo : public RenderPassInfoBase {
|
||||
public:
|
||||
struct OMSetRenderTargetArgs {
|
||||
unsigned int numRTVs = 0;
|
||||
|
@ -36,20 +36,17 @@ namespace backend { namespace d3d12 {
|
|||
D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
|
||||
};
|
||||
|
||||
Framebuffer(Device* device, FramebufferBuilder* builder);
|
||||
OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs(uint32_t subpassIndex);
|
||||
RenderPassInfo(Device* device, RenderPassInfoBuilder* builder);
|
||||
OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs();
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE GetRTVDescriptor(uint32_t attachmentSlot);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE GetDSVDescriptor(uint32_t attachmentSlot);
|
||||
D3D12_CPU_DESCRIPTOR_HANDLE GetDSVDescriptor();
|
||||
|
||||
private:
|
||||
Device* mDevice = nullptr;
|
||||
DescriptorHeapHandle mRtvHeap = {};
|
||||
DescriptorHeapHandle mDsvHeap = {};
|
||||
|
||||
// Indices into either the RTV or DSV heap, depending on texture format.
|
||||
std::vector<uint32_t> mAttachmentHeapIndices;
|
||||
};
|
||||
|
||||
}} // namespace backend::d3d12
|
||||
|
||||
#endif // BACKEND_D3D12_FRAMEBUFFERD3D12_H_
|
||||
#endif // BACKEND_D3D12_RENDERPASSINFOD3D12_H_
|
|
@ -136,26 +136,16 @@ namespace backend { namespace d3d12 {
|
|||
descriptor.RasterizerState.ForcedSampleCount = 0;
|
||||
descriptor.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
|
||||
|
||||
RenderPass* renderPass = ToBackend(GetRenderPass());
|
||||
auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
|
||||
|
||||
if (subpassInfo.depthStencilAttachmentSet) {
|
||||
const auto& attachmentInfo =
|
||||
renderPass->GetAttachmentInfo(subpassInfo.depthStencilAttachment);
|
||||
descriptor.DSVFormat = D3D12TextureFormat(attachmentInfo.format);
|
||||
if (HasDepthStencilAttachment()) {
|
||||
descriptor.DSVFormat = D3D12TextureFormat(GetDepthStencilFormat());
|
||||
}
|
||||
|
||||
unsigned int attachmentCount = 0;
|
||||
for (unsigned int attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
||||
uint32_t attachment = subpassInfo.colorAttachments[attachmentSlot];
|
||||
const auto& attachmentInfo = renderPass->GetAttachmentInfo(attachment);
|
||||
|
||||
descriptor.RTVFormats[attachmentSlot] = D3D12TextureFormat(attachmentInfo.format);
|
||||
descriptor.BlendState.RenderTarget[attachmentSlot] =
|
||||
ToBackend(GetBlendState(attachmentSlot))->GetD3D12BlendDesc();
|
||||
attachmentCount = attachmentSlot + 1;
|
||||
for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
|
||||
descriptor.RTVFormats[i] = D3D12TextureFormat(GetColorAttachmentFormat(i));
|
||||
descriptor.BlendState.RenderTarget[i] =
|
||||
ToBackend(GetBlendState(i))->GetD3D12BlendDesc();
|
||||
}
|
||||
descriptor.NumRenderTargets = attachmentCount;
|
||||
descriptor.NumRenderTargets = static_cast<uint32_t>(GetColorAttachmentsMask().count());
|
||||
|
||||
descriptor.BlendState.AlphaToCoverageEnable = FALSE;
|
||||
descriptor.BlendState.IndependentBlendEnable = TRUE;
|
||||
|
|
|
@ -35,9 +35,6 @@ namespace backend { namespace metal {
|
|||
id<MTLComputeCommandEncoder> compute = nil;
|
||||
id<MTLRenderCommandEncoder> render = nil;
|
||||
|
||||
RenderPass* currentRenderPass = nullptr;
|
||||
Framebuffer* currentFramebuffer = nullptr;
|
||||
|
||||
void EnsureNoBlitEncoder() {
|
||||
ASSERT(render == nil);
|
||||
ASSERT(compute == nil);
|
||||
|
@ -67,59 +64,46 @@ namespace backend { namespace metal {
|
|||
compute = nil; // This will be autoreleased.
|
||||
}
|
||||
|
||||
void BeginSubpass(id<MTLCommandBuffer> commandBuffer, uint32_t subpass) {
|
||||
ASSERT(currentRenderPass);
|
||||
void BeginRenderPass(id<MTLCommandBuffer> commandBuffer, RenderPassInfo* info) {
|
||||
if (render != nil) {
|
||||
[render endEncoding];
|
||||
render = nil; // This will be autoreleased.
|
||||
}
|
||||
|
||||
const auto& info = currentRenderPass->GetSubpassInfo(subpass);
|
||||
|
||||
MTLRenderPassDescriptor* descriptor =
|
||||
[MTLRenderPassDescriptor renderPassDescriptor];
|
||||
for (unsigned int location : IterateBitSet(info.colorAttachmentsSet)) {
|
||||
uint32_t attachment = info.colorAttachments[location];
|
||||
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachment);
|
||||
|
||||
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
||||
auto texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
||||
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
|
||||
auto& attachmentInfo = info->GetColorAttachment(i);
|
||||
|
||||
bool isFirstUse = attachmentInfo.firstSubpass == subpass;
|
||||
bool shouldClearOnFirstUse = attachmentInfo.colorLoadOp == nxt::LoadOp::Clear;
|
||||
if (isFirstUse && shouldClearOnFirstUse) {
|
||||
auto clearValue = currentFramebuffer->GetClearColor(location);
|
||||
descriptor.colorAttachments[location].loadAction = MTLLoadActionClear;
|
||||
descriptor.colorAttachments[location].clearColor =
|
||||
MTLClearColorMake(clearValue.color[0], clearValue.color[1],
|
||||
clearValue.color[2], clearValue.color[3]);
|
||||
if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
|
||||
descriptor.colorAttachments[i].loadAction = MTLLoadActionClear;
|
||||
descriptor.colorAttachments[i].clearColor = MTLClearColorMake(
|
||||
attachmentInfo.clearColor[0], attachmentInfo.clearColor[1],
|
||||
attachmentInfo.clearColor[2], attachmentInfo.clearColor[3]);
|
||||
} else {
|
||||
descriptor.colorAttachments[location].loadAction = MTLLoadActionLoad;
|
||||
descriptor.colorAttachments[i].loadAction = MTLLoadActionLoad;
|
||||
}
|
||||
|
||||
descriptor.colorAttachments[location].texture = texture;
|
||||
descriptor.colorAttachments[location].storeAction = MTLStoreActionStore;
|
||||
descriptor.colorAttachments[i].texture =
|
||||
ToBackend(attachmentInfo.view->GetTexture())->GetMTLTexture();
|
||||
descriptor.colorAttachments[i].storeAction = MTLStoreActionStore;
|
||||
}
|
||||
if (info.depthStencilAttachmentSet) {
|
||||
uint32_t attachment = info.depthStencilAttachment;
|
||||
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachment);
|
||||
|
||||
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
||||
id<MTLTexture> texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
||||
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
|
||||
if (info->HasDepthStencilAttachment()) {
|
||||
auto& attachmentInfo = info->GetDepthStencilAttachment();
|
||||
|
||||
bool isFirstUse = attachmentInfo.firstSubpass == subpass;
|
||||
const auto& clearValues = currentFramebuffer->GetClearDepthStencil(attachment);
|
||||
id<MTLTexture> texture =
|
||||
ToBackend(attachmentInfo.view->GetTexture())->GetMTLTexture();
|
||||
nxt::TextureFormat format = attachmentInfo.view->GetTexture()->GetFormat();
|
||||
|
||||
if (TextureFormatHasDepth(format)) {
|
||||
descriptor.depthAttachment.texture = texture;
|
||||
descriptor.depthAttachment.storeAction = MTLStoreActionStore;
|
||||
|
||||
bool shouldClearDepthOnFirstUse =
|
||||
attachmentInfo.depthLoadOp == nxt::LoadOp::Clear;
|
||||
if (isFirstUse && shouldClearDepthOnFirstUse) {
|
||||
if (attachmentInfo.depthLoadOp == nxt::LoadOp::Clear) {
|
||||
descriptor.depthAttachment.loadAction = MTLLoadActionClear;
|
||||
descriptor.depthAttachment.clearDepth = clearValues.depth;
|
||||
descriptor.depthAttachment.clearDepth = attachmentInfo.clearDepth;
|
||||
} else {
|
||||
descriptor.depthAttachment.loadAction = MTLLoadActionLoad;
|
||||
}
|
||||
|
@ -129,11 +113,9 @@ namespace backend { namespace metal {
|
|||
descriptor.stencilAttachment.texture = texture;
|
||||
descriptor.stencilAttachment.storeAction = MTLStoreActionStore;
|
||||
|
||||
bool shouldClearStencilOnFirstUse =
|
||||
attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear;
|
||||
if (isFirstUse && shouldClearStencilOnFirstUse) {
|
||||
if (attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear) {
|
||||
descriptor.stencilAttachment.loadAction = MTLLoadActionClear;
|
||||
descriptor.stencilAttachment.clearStencil = clearValues.stencil;
|
||||
descriptor.stencilAttachment.clearStencil = attachmentInfo.clearStencil;
|
||||
} else {
|
||||
descriptor.stencilAttachment.loadAction = MTLLoadActionLoad;
|
||||
}
|
||||
|
@ -144,7 +126,7 @@ namespace backend { namespace metal {
|
|||
// TODO(cwallez@chromium.org): does any state need to be reset?
|
||||
}
|
||||
|
||||
void EndSubpass() {
|
||||
void EndRenderPass() {
|
||||
ASSERT(render != nil);
|
||||
[render endEncoding];
|
||||
render = nil; // This will be autoreleased.
|
||||
|
@ -174,7 +156,6 @@ namespace backend { namespace metal {
|
|||
|
||||
PerStage<std::array<uint32_t, kMaxPushConstants>> pushConstants;
|
||||
|
||||
uint32_t currentSubpass = 0;
|
||||
while (mCommands.NextCommandId(&type)) {
|
||||
switch (type) {
|
||||
case Command::BeginComputePass: {
|
||||
|
@ -190,15 +171,11 @@ namespace backend { namespace metal {
|
|||
case Command::BeginRenderPass: {
|
||||
BeginRenderPassCmd* beginRenderPassCmd =
|
||||
mCommands.NextCommand<BeginRenderPassCmd>();
|
||||
encoders.currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
|
||||
encoders.currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
|
||||
encoders.EnsureNoBlitEncoder();
|
||||
currentSubpass = 0;
|
||||
} break;
|
||||
|
||||
case Command::BeginRenderSubpass: {
|
||||
mCommands.NextCommand<BeginRenderSubpassCmd>();
|
||||
encoders.BeginSubpass(commandBuffer, currentSubpass);
|
||||
RenderPassInfo* info = ToBackend(beginRenderPassCmd->info.Get());
|
||||
|
||||
encoders.EnsureNoBlitEncoder();
|
||||
encoders.BeginRenderPass(commandBuffer, info);
|
||||
|
||||
pushConstants[nxt::ShaderStage::Vertex].fill(0);
|
||||
pushConstants[nxt::ShaderStage::Fragment].fill(0);
|
||||
|
@ -325,12 +302,7 @@ namespace backend { namespace metal {
|
|||
|
||||
case Command::EndRenderPass: {
|
||||
mCommands.NextCommand<EndRenderPassCmd>();
|
||||
} break;
|
||||
|
||||
case Command::EndRenderSubpass: {
|
||||
mCommands.NextCommand<EndRenderSubpassCmd>();
|
||||
encoders.EndSubpass();
|
||||
currentSubpass += 1;
|
||||
encoders.EndRenderPass();
|
||||
} break;
|
||||
|
||||
case Command::SetComputePipeline: {
|
||||
|
|
|
@ -20,9 +20,8 @@
|
|||
#include "backend/BindGroup.h"
|
||||
#include "backend/BindGroupLayout.h"
|
||||
#include "backend/Device.h"
|
||||
#include "backend/Framebuffer.h"
|
||||
#include "backend/Queue.h"
|
||||
#include "backend/RenderPass.h"
|
||||
#include "backend/RenderPassInfo.h"
|
||||
#include "backend/ToBackend.h"
|
||||
#include "common/Serial.h"
|
||||
|
||||
|
@ -45,7 +44,7 @@ namespace backend { namespace metal {
|
|||
class InputState;
|
||||
class PipelineLayout;
|
||||
class Queue;
|
||||
class RenderPass;
|
||||
class RenderPassInfo;
|
||||
class RenderPipeline;
|
||||
class Sampler;
|
||||
class ShaderModule;
|
||||
|
@ -63,11 +62,10 @@ namespace backend { namespace metal {
|
|||
using ComputePipelineType = ComputePipeline;
|
||||
using DepthStencilStateType = DepthStencilState;
|
||||
using DeviceType = Device;
|
||||
using FramebufferType = Framebuffer;
|
||||
using InputStateType = InputState;
|
||||
using PipelineLayoutType = PipelineLayout;
|
||||
using QueueType = Queue;
|
||||
using RenderPassType = RenderPass;
|
||||
using RenderPassInfoType = RenderPassInfo;
|
||||
using RenderPipelineType = RenderPipeline;
|
||||
using SamplerType = Sampler;
|
||||
using ShaderModuleType = ShaderModule;
|
||||
|
@ -98,10 +96,9 @@ namespace backend { namespace metal {
|
|||
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
|
||||
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
|
||||
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
|
||||
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
|
||||
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
|
||||
QueueBase* CreateQueue(QueueBuilder* builder) override;
|
||||
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
|
||||
RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
|
||||
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
||||
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
|
||||
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
|
||||
|
@ -143,12 +140,6 @@ namespace backend { namespace metal {
|
|||
BindGroupLayout(BindGroupLayoutBuilder* builder);
|
||||
};
|
||||
|
||||
class Framebuffer : public FramebufferBase {
|
||||
public:
|
||||
Framebuffer(FramebufferBuilder* builder);
|
||||
~Framebuffer();
|
||||
};
|
||||
|
||||
class Queue : public QueueBase {
|
||||
public:
|
||||
Queue(QueueBuilder* builder);
|
||||
|
@ -163,10 +154,10 @@ namespace backend { namespace metal {
|
|||
id<MTLCommandQueue> mCommandQueue = nil;
|
||||
};
|
||||
|
||||
class RenderPass : public RenderPassBase {
|
||||
class RenderPassInfo : public RenderPassInfoBase {
|
||||
public:
|
||||
RenderPass(RenderPassBuilder* builder);
|
||||
~RenderPass();
|
||||
RenderPassInfo(RenderPassInfoBuilder* builder);
|
||||
~RenderPassInfo();
|
||||
};
|
||||
|
||||
}} // namespace backend::metal
|
||||
|
|
|
@ -101,9 +101,6 @@ namespace backend { namespace metal {
|
|||
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
|
||||
return new DepthStencilState(builder);
|
||||
}
|
||||
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
|
||||
return new Framebuffer(builder);
|
||||
}
|
||||
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
|
||||
return new InputState(builder);
|
||||
}
|
||||
|
@ -113,8 +110,8 @@ namespace backend { namespace metal {
|
|||
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
|
||||
return new Queue(builder);
|
||||
}
|
||||
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
|
||||
return new RenderPass(builder);
|
||||
RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
|
||||
return new RenderPassInfo(builder);
|
||||
}
|
||||
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
|
||||
return new RenderPipeline(builder);
|
||||
|
@ -202,14 +199,6 @@ namespace backend { namespace metal {
|
|||
: BindGroupLayoutBase(builder) {
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
|
||||
Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer() {
|
||||
}
|
||||
|
||||
// Queue
|
||||
|
||||
Queue::Queue(QueueBuilder* builder) : QueueBase(builder) {
|
||||
|
@ -240,10 +229,10 @@ namespace backend { namespace metal {
|
|||
|
||||
// RenderPass
|
||||
|
||||
RenderPass::RenderPass(RenderPassBuilder* builder) : RenderPassBase(builder) {
|
||||
RenderPassInfo::RenderPassInfo(RenderPassInfoBuilder* builder) : RenderPassInfoBase(builder) {
|
||||
}
|
||||
|
||||
RenderPass::~RenderPass() {
|
||||
RenderPassInfo::~RenderPassInfo() {
|
||||
}
|
||||
|
||||
}} // namespace backend::metal
|
||||
|
|
|
@ -92,24 +92,17 @@ namespace backend { namespace metal {
|
|||
}
|
||||
}
|
||||
|
||||
RenderPass* renderPass = ToBackend(GetRenderPass());
|
||||
auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
|
||||
|
||||
if (subpassInfo.depthStencilAttachmentSet) {
|
||||
const auto& attachmentInfo =
|
||||
renderPass->GetAttachmentInfo(subpassInfo.depthStencilAttachment);
|
||||
descriptor.depthAttachmentPixelFormat = MetalPixelFormat(attachmentInfo.format);
|
||||
descriptor.stencilAttachmentPixelFormat = MetalPixelFormat(attachmentInfo.format);
|
||||
if (HasDepthStencilAttachment()) {
|
||||
// TODO(kainino@chromium.org): Handle depth-only and stencil-only formats.
|
||||
nxt::TextureFormat depthStencilFormat = GetDepthStencilFormat();
|
||||
descriptor.depthAttachmentPixelFormat = MetalPixelFormat(depthStencilFormat);
|
||||
descriptor.stencilAttachmentPixelFormat = MetalPixelFormat(depthStencilFormat);
|
||||
}
|
||||
|
||||
for (unsigned int attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
||||
uint32_t attachment = subpassInfo.colorAttachments[attachmentSlot];
|
||||
const auto& attachmentInfo = renderPass->GetAttachmentInfo(attachment);
|
||||
|
||||
descriptor.colorAttachments[attachmentSlot].pixelFormat =
|
||||
MetalPixelFormat(attachmentInfo.format);
|
||||
ToBackend(GetBlendState(attachmentSlot))
|
||||
->ApplyBlendState(descriptor.colorAttachments[attachmentSlot]);
|
||||
for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
|
||||
descriptor.colorAttachments[i].pixelFormat =
|
||||
MetalPixelFormat(GetColorAttachmentFormat(i));
|
||||
ToBackend(GetBlendState(i))->ApplyBlendState(descriptor.colorAttachments[i]);
|
||||
}
|
||||
|
||||
descriptor.inputPrimitiveTopology = MTLInputPrimitiveTopology(GetPrimitiveTopology());
|
||||
|
|
|
@ -60,9 +60,6 @@ namespace backend { namespace null {
|
|||
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
|
||||
return new DepthStencilState(builder);
|
||||
}
|
||||
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
|
||||
return new Framebuffer(builder);
|
||||
}
|
||||
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
|
||||
return new InputState(builder);
|
||||
}
|
||||
|
@ -72,8 +69,8 @@ namespace backend { namespace null {
|
|||
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
|
||||
return new Queue(builder);
|
||||
}
|
||||
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
|
||||
return new RenderPass(builder);
|
||||
RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
|
||||
return new RenderPassInfo(builder);
|
||||
}
|
||||
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
|
||||
return new RenderPipeline(builder);
|
||||
|
|
|
@ -25,11 +25,10 @@
|
|||
#include "backend/ComputePipeline.h"
|
||||
#include "backend/DepthStencilState.h"
|
||||
#include "backend/Device.h"
|
||||
#include "backend/Framebuffer.h"
|
||||
#include "backend/InputState.h"
|
||||
#include "backend/PipelineLayout.h"
|
||||
#include "backend/Queue.h"
|
||||
#include "backend/RenderPass.h"
|
||||
#include "backend/RenderPassInfo.h"
|
||||
#include "backend/RenderPipeline.h"
|
||||
#include "backend/Sampler.h"
|
||||
#include "backend/ShaderModule.h"
|
||||
|
@ -48,11 +47,10 @@ namespace backend { namespace null {
|
|||
using ComputePipeline = ComputePipelineBase;
|
||||
using DepthStencilState = DepthStencilStateBase;
|
||||
class Device;
|
||||
using Framebuffer = FramebufferBase;
|
||||
using InputState = InputStateBase;
|
||||
using PipelineLayout = PipelineLayoutBase;
|
||||
class Queue;
|
||||
using RenderPass = RenderPassBase;
|
||||
using RenderPassInfo = RenderPassInfoBase;
|
||||
using RenderPipeline = RenderPipelineBase;
|
||||
using Sampler = SamplerBase;
|
||||
using ShaderModule = ShaderModuleBase;
|
||||
|
@ -70,11 +68,10 @@ namespace backend { namespace null {
|
|||
using ComputePipelineType = ComputePipeline;
|
||||
using DepthStencilStateType = DepthStencilState;
|
||||
using DeviceType = Device;
|
||||
using FramebufferType = Framebuffer;
|
||||
using InputStateType = InputState;
|
||||
using PipelineLayoutType = PipelineLayout;
|
||||
using QueueType = Queue;
|
||||
using RenderPassType = RenderPass;
|
||||
using RenderPassInfoType = RenderPassInfo;
|
||||
using RenderPipelineType = RenderPipeline;
|
||||
using SamplerType = Sampler;
|
||||
using ShaderModuleType = ShaderModule;
|
||||
|
@ -106,11 +103,10 @@ namespace backend { namespace null {
|
|||
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
|
||||
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
|
||||
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
|
||||
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
|
||||
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
|
||||
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
|
||||
QueueBase* CreateQueue(QueueBuilder* builder) override;
|
||||
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
|
||||
RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
|
||||
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
||||
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
|
||||
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
|
||||
|
|
|
@ -254,9 +254,6 @@ namespace backend { namespace opengl {
|
|||
PushConstantTracker pushConstants;
|
||||
InputBufferTracker inputBuffers;
|
||||
|
||||
RenderPass* currentRenderPass = nullptr;
|
||||
Framebuffer* currentFramebuffer = nullptr;
|
||||
uint32_t currentSubpass = 0;
|
||||
GLuint currentFBO = 0;
|
||||
|
||||
while (mCommands.NextCommandId(&type)) {
|
||||
|
@ -268,13 +265,8 @@ namespace backend { namespace opengl {
|
|||
|
||||
case Command::BeginRenderPass: {
|
||||
auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
|
||||
currentRenderPass = ToBackend(cmd->renderPass.Get());
|
||||
currentFramebuffer = ToBackend(cmd->framebuffer.Get());
|
||||
currentSubpass = 0;
|
||||
} break;
|
||||
RenderPassInfo* info = ToBackend(cmd->info.Get());
|
||||
|
||||
case Command::BeginRenderSubpass: {
|
||||
mCommands.NextCommand<BeginRenderSubpassCmd>();
|
||||
pushConstants.OnBeginPass();
|
||||
inputBuffers.OnBeginPass();
|
||||
|
||||
|
@ -292,8 +284,6 @@ namespace backend { namespace opengl {
|
|||
glGenFramebuffers(1, ¤tFBO);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
|
||||
|
||||
const auto& subpass = currentRenderPass->GetSubpassInfo(currentSubpass);
|
||||
|
||||
// Mapping from attachmentSlot to GL framebuffer
|
||||
// attachment points. Defaults to zero (GL_NONE).
|
||||
std::array<GLenum, kMaxColorAttachments> drawBuffers = {};
|
||||
|
@ -301,17 +291,15 @@ namespace backend { namespace opengl {
|
|||
// Construct GL framebuffer
|
||||
|
||||
unsigned int attachmentCount = 0;
|
||||
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
|
||||
uint32_t attachment = subpass.colorAttachments[location];
|
||||
|
||||
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
||||
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
|
||||
TextureViewBase* textureView = info->GetColorAttachment(i).view.Get();
|
||||
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
|
||||
|
||||
// Attach color buffers.
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + location,
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
|
||||
GL_TEXTURE_2D, texture, 0);
|
||||
drawBuffers[location] = GL_COLOR_ATTACHMENT0 + location;
|
||||
attachmentCount = location + 1;
|
||||
drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
|
||||
attachmentCount = i + 1;
|
||||
|
||||
// TODO(kainino@chromium.org): the color clears (later in
|
||||
// this function) may be undefined for non-normalized integer formats.
|
||||
|
@ -323,10 +311,8 @@ namespace backend { namespace opengl {
|
|||
}
|
||||
glDrawBuffers(attachmentCount, drawBuffers.data());
|
||||
|
||||
if (subpass.depthStencilAttachmentSet) {
|
||||
uint32_t attachmentSlot = subpass.depthStencilAttachment;
|
||||
|
||||
auto textureView = currentFramebuffer->GetTextureView(attachmentSlot);
|
||||
if (info->HasDepthStencilAttachment()) {
|
||||
TextureViewBase* textureView = info->GetDepthStencilAttachment().view.Get();
|
||||
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
|
||||
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
|
||||
|
||||
|
@ -354,52 +340,39 @@ namespace backend { namespace opengl {
|
|||
|
||||
// Clear framebuffer attachments as needed
|
||||
|
||||
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
|
||||
uint32_t attachmentSlot = subpass.colorAttachments[location];
|
||||
const auto& attachmentInfo =
|
||||
currentRenderPass->GetAttachmentInfo(attachmentSlot);
|
||||
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
|
||||
const auto& attachmentInfo = info->GetColorAttachment(i);
|
||||
|
||||
// Only perform load op on first use
|
||||
if (attachmentInfo.firstSubpass == currentSubpass) {
|
||||
// Load op - color
|
||||
if (attachmentInfo.colorLoadOp == nxt::LoadOp::Clear) {
|
||||
const auto& clear = currentFramebuffer->GetClearColor(location);
|
||||
glClearBufferfv(GL_COLOR, location, clear.color);
|
||||
}
|
||||
// Load op - color
|
||||
if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
|
||||
glClearBufferfv(GL_COLOR, i, attachmentInfo.clearColor.data());
|
||||
}
|
||||
}
|
||||
|
||||
if (subpass.depthStencilAttachmentSet) {
|
||||
uint32_t attachmentSlot = subpass.depthStencilAttachment;
|
||||
const auto& attachmentInfo =
|
||||
currentRenderPass->GetAttachmentInfo(attachmentSlot);
|
||||
if (info->HasDepthStencilAttachment()) {
|
||||
const auto& attachmentInfo = info->GetDepthStencilAttachment();
|
||||
nxt::TextureFormat attachmentFormat =
|
||||
attachmentInfo.view->GetTexture()->GetFormat();
|
||||
|
||||
// Only perform load op on first use
|
||||
if (attachmentInfo.firstSubpass == currentSubpass) {
|
||||
// Load op - depth/stencil
|
||||
const auto& clear = currentFramebuffer->GetClearDepthStencil(
|
||||
subpass.depthStencilAttachment);
|
||||
bool doDepthClear = TextureFormatHasDepth(attachmentInfo.format) &&
|
||||
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
|
||||
bool doStencilClear =
|
||||
TextureFormatHasStencil(attachmentInfo.format) &&
|
||||
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
|
||||
if (doDepthClear && doStencilClear) {
|
||||
glClearBufferfi(GL_DEPTH_STENCIL, 0, clear.depth, clear.stencil);
|
||||
} else if (doDepthClear) {
|
||||
glClearBufferfv(GL_DEPTH, 0, &clear.depth);
|
||||
} else if (doStencilClear) {
|
||||
const GLint clearStencil = clear.stencil;
|
||||
glClearBufferiv(GL_STENCIL, 0, &clearStencil);
|
||||
}
|
||||
// Load op - depth/stencil
|
||||
bool doDepthClear = TextureFormatHasDepth(attachmentFormat) &&
|
||||
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
|
||||
bool doStencilClear = TextureFormatHasStencil(attachmentFormat) &&
|
||||
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
|
||||
if (doDepthClear && doStencilClear) {
|
||||
glClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo.clearDepth,
|
||||
attachmentInfo.clearStencil);
|
||||
} else if (doDepthClear) {
|
||||
glClearBufferfv(GL_DEPTH, 0, &attachmentInfo.clearDepth);
|
||||
} else if (doStencilClear) {
|
||||
const GLint clearStencil = attachmentInfo.clearStencil;
|
||||
glClearBufferiv(GL_STENCIL, 0, &clearStencil);
|
||||
}
|
||||
}
|
||||
|
||||
glBlendColor(0, 0, 0, 0);
|
||||
glViewport(0, 0, currentFramebuffer->GetWidth(),
|
||||
currentFramebuffer->GetHeight());
|
||||
glScissor(0, 0, currentFramebuffer->GetWidth(),
|
||||
currentFramebuffer->GetHeight());
|
||||
glViewport(0, 0, info->GetWidth(), info->GetHeight());
|
||||
glScissor(0, 0, info->GetWidth(), info->GetHeight());
|
||||
} break;
|
||||
|
||||
case Command::CopyBufferToBuffer: {
|
||||
|
@ -530,13 +503,8 @@ namespace backend { namespace opengl {
|
|||
|
||||
case Command::EndRenderPass: {
|
||||
mCommands.NextCommand<EndRenderPassCmd>();
|
||||
} break;
|
||||
|
||||
case Command::EndRenderSubpass: {
|
||||
mCommands.NextCommand<EndRenderSubpassCmd>();
|
||||
glDeleteFramebuffers(1, ¤tFBO);
|
||||
currentFBO = 0;
|
||||
currentSubpass += 1;
|
||||
} break;
|
||||
|
||||
case Command::SetComputePipeline: {
|
||||
|
|
|
@ -73,17 +73,14 @@ namespace backend { namespace opengl {
|
|||
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
|
||||
return new InputState(builder);
|
||||
}
|
||||
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
|
||||
return new Framebuffer(builder);
|
||||
}
|
||||
PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
|
||||
return new PipelineLayout(builder);
|
||||
}
|
||||
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
|
||||
return new Queue(builder);
|
||||
}
|
||||
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
|
||||
return new RenderPass(builder);
|
||||
RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
|
||||
return new RenderPassInfo(builder);
|
||||
}
|
||||
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
|
||||
return new RenderPipeline(builder);
|
||||
|
@ -118,11 +115,6 @@ namespace backend { namespace opengl {
|
|||
: BindGroupLayoutBase(builder) {
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
|
||||
Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
|
||||
}
|
||||
|
||||
// Queue
|
||||
|
||||
Queue::Queue(QueueBuilder* builder) : QueueBase(builder) {
|
||||
|
@ -134,9 +126,9 @@ namespace backend { namespace opengl {
|
|||
}
|
||||
}
|
||||
|
||||
// RenderPass
|
||||
// RenderPassInfo
|
||||
|
||||
RenderPass::RenderPass(RenderPassBuilder* builder) : RenderPassBase(builder) {
|
||||
RenderPassInfo::RenderPassInfo(RenderPassInfoBuilder* builder) : RenderPassInfoBase(builder) {
|
||||
}
|
||||
|
||||
}} // namespace backend::opengl
|
||||
|
|
|
@ -23,10 +23,9 @@
|
|||
#include "backend/Buffer.h"
|
||||
#include "backend/DepthStencilState.h"
|
||||
#include "backend/Device.h"
|
||||
#include "backend/Framebuffer.h"
|
||||
#include "backend/InputState.h"
|
||||
#include "backend/Queue.h"
|
||||
#include "backend/RenderPass.h"
|
||||
#include "backend/RenderPassInfo.h"
|
||||
#include "backend/ToBackend.h"
|
||||
|
||||
#include "glad/glad.h"
|
||||
|
@ -42,12 +41,11 @@ namespace backend { namespace opengl {
|
|||
class ComputePipeline;
|
||||
class DepthStencilState;
|
||||
class Device;
|
||||
class Framebuffer;
|
||||
class InputState;
|
||||
class PersistentPipelineState;
|
||||
class PipelineLayout;
|
||||
class Queue;
|
||||
class RenderPass;
|
||||
class RenderPassInfo;
|
||||
class RenderPipeline;
|
||||
class Sampler;
|
||||
class ShaderModule;
|
||||
|
@ -65,11 +63,10 @@ namespace backend { namespace opengl {
|
|||
using ComputePipelineType = ComputePipeline;
|
||||
using DepthStencilStateType = DepthStencilState;
|
||||
using DeviceType = Device;
|
||||
using FramebufferType = Framebuffer;
|
||||
using InputStateType = InputState;
|
||||
using PipelineLayoutType = PipelineLayout;
|
||||
using QueueType = Queue;
|
||||
using RenderPassType = RenderPass;
|
||||
using RenderPassInfoType = RenderPassInfo;
|
||||
using RenderPipelineType = RenderPipeline;
|
||||
using SamplerType = Sampler;
|
||||
using ShaderModuleType = ShaderModule;
|
||||
|
@ -95,10 +92,9 @@ namespace backend { namespace opengl {
|
|||
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
|
||||
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
|
||||
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
|
||||
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
|
||||
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
|
||||
QueueBase* CreateQueue(QueueBuilder* builder) override;
|
||||
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
|
||||
RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
|
||||
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
||||
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
|
||||
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
|
||||
|
@ -119,11 +115,6 @@ namespace backend { namespace opengl {
|
|||
BindGroupLayout(BindGroupLayoutBuilder* builder);
|
||||
};
|
||||
|
||||
class Framebuffer : public FramebufferBase {
|
||||
public:
|
||||
Framebuffer(FramebufferBuilder* builder);
|
||||
};
|
||||
|
||||
class Queue : public QueueBase {
|
||||
public:
|
||||
Queue(QueueBuilder* builder);
|
||||
|
@ -132,9 +123,9 @@ namespace backend { namespace opengl {
|
|||
void Submit(uint32_t numCommands, CommandBuffer* const* commands);
|
||||
};
|
||||
|
||||
class RenderPass : public RenderPassBase {
|
||||
class RenderPassInfo : public RenderPassInfoBase {
|
||||
public:
|
||||
RenderPass(RenderPassBuilder* builder);
|
||||
RenderPassInfo(RenderPassInfoBuilder* builder);
|
||||
};
|
||||
|
||||
}} // namespace backend::opengl
|
||||
|
|
|
@ -60,10 +60,7 @@ namespace backend { namespace opengl {
|
|||
auto depthStencilState = ToBackend(GetDepthStencilState());
|
||||
depthStencilState->ApplyNow(persistentPipelineState);
|
||||
|
||||
RenderPass* renderPass = ToBackend(GetRenderPass());
|
||||
auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
|
||||
|
||||
for (uint32_t attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
||||
for (uint32_t attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
|
||||
ToBackend(GetBlendState(attachmentSlot))->ApplyNow(attachmentSlot);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,8 @@
|
|||
#include "backend/vulkan/BindGroupVk.h"
|
||||
#include "backend/vulkan/BufferVk.h"
|
||||
#include "backend/vulkan/ComputePipelineVk.h"
|
||||
#include "backend/vulkan/FramebufferVk.h"
|
||||
#include "backend/vulkan/PipelineLayoutVk.h"
|
||||
#include "backend/vulkan/RenderPassVk.h"
|
||||
#include "backend/vulkan/RenderPassInfoVk.h"
|
||||
#include "backend/vulkan/RenderPipelineVk.h"
|
||||
#include "backend/vulkan/TextureVk.h"
|
||||
#include "backend/vulkan/VulkanBackend.h"
|
||||
|
@ -184,43 +183,32 @@ namespace backend { namespace vulkan {
|
|||
|
||||
case Command::BeginRenderPass: {
|
||||
BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
|
||||
Framebuffer* framebuffer = ToBackend(cmd->framebuffer.Get());
|
||||
RenderPass* renderPass = ToBackend(cmd->renderPass.Get());
|
||||
RenderPassInfo* info = ToBackend(cmd->info.Get());
|
||||
|
||||
// NXT has an implicit transition to color attachment on subpasses. Transition
|
||||
// the attachments now before we start the render pass.
|
||||
for (uint32_t i = 0; i < renderPass->GetAttachmentCount(); ++i) {
|
||||
// NXT has an implicit transition to color attachment on render passes.
|
||||
// Transition the attachments now before we start the render pass.
|
||||
for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
|
||||
Texture* attachment =
|
||||
ToBackend(framebuffer->GetTextureView(i)->GetTexture());
|
||||
ToBackend(info->GetColorAttachment(i).view->GetTexture());
|
||||
|
||||
if (attachment->GetUsage() & nxt::TextureUsageBit::OutputAttachment) {
|
||||
continue;
|
||||
if (!(attachment->GetUsage() & nxt::TextureUsageBit::OutputAttachment)) {
|
||||
attachment->RecordBarrier(commands, attachment->GetUsage(),
|
||||
nxt::TextureUsageBit::OutputAttachment);
|
||||
attachment->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
|
||||
}
|
||||
}
|
||||
if (info->HasDepthStencilAttachment()) {
|
||||
Texture* attachment =
|
||||
ToBackend(info->GetDepthStencilAttachment().view->GetTexture());
|
||||
|
||||
attachment->RecordBarrier(commands, attachment->GetUsage(),
|
||||
nxt::TextureUsageBit::OutputAttachment);
|
||||
attachment->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
|
||||
if (!(attachment->GetUsage() & nxt::TextureUsageBit::OutputAttachment)) {
|
||||
attachment->RecordBarrier(commands, attachment->GetUsage(),
|
||||
nxt::TextureUsageBit::OutputAttachment);
|
||||
attachment->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(renderPass->GetSubpassCount() == 1);
|
||||
ASSERT(renderPass->GetAttachmentCount() <= kMaxColorAttachments + 1);
|
||||
|
||||
std::array<VkClearValue, kMaxColorAttachments + 1> clearValues;
|
||||
framebuffer->FillClearValues(clearValues.data());
|
||||
|
||||
VkRenderPassBeginInfo beginInfo;
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
beginInfo.pNext = nullptr;
|
||||
beginInfo.renderPass = renderPass->GetHandle();
|
||||
beginInfo.framebuffer = framebuffer->GetHandle();
|
||||
beginInfo.renderArea.offset.x = 0;
|
||||
beginInfo.renderArea.offset.y = 0;
|
||||
beginInfo.renderArea.extent.width = framebuffer->GetWidth();
|
||||
beginInfo.renderArea.extent.height = framebuffer->GetHeight();
|
||||
beginInfo.clearValueCount = renderPass->GetAttachmentCount();
|
||||
beginInfo.pClearValues = clearValues.data();
|
||||
|
||||
device->fn.CmdBeginRenderPass(commands, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
info->RecordBeginRenderPass(commands);
|
||||
|
||||
// Set all the dynamic state just in case.
|
||||
device->fn.CmdSetLineWidth(commands, 1.0f);
|
||||
|
@ -228,32 +216,6 @@ namespace backend { namespace vulkan {
|
|||
|
||||
device->fn.CmdSetStencilReference(commands, VK_STENCIL_FRONT_AND_BACK, 0);
|
||||
|
||||
// The viewport and scissor default to cover all of the attachments
|
||||
VkViewport viewport;
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(framebuffer->GetWidth());
|
||||
viewport.height = static_cast<float>(framebuffer->GetHeight());
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
device->fn.CmdSetViewport(commands, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissorRect;
|
||||
scissorRect.offset.x = 0;
|
||||
scissorRect.offset.y = 0;
|
||||
scissorRect.extent.width = framebuffer->GetWidth();
|
||||
scissorRect.extent.height = framebuffer->GetHeight();
|
||||
device->fn.CmdSetScissor(commands, 0, 1, &scissorRect);
|
||||
|
||||
descriptorSets.OnBeginPass();
|
||||
} break;
|
||||
|
||||
case Command::BeginRenderSubpass: {
|
||||
mCommands.NextCommand<BeginRenderSubpassCmd>();
|
||||
// Do nothing related to subpasses because the single subpass is started in
|
||||
// vkBeginRenderPass
|
||||
|
||||
// Set up the default state
|
||||
float blendConstants[4] = {
|
||||
0.0f,
|
||||
0.0f,
|
||||
|
@ -261,6 +223,25 @@ namespace backend { namespace vulkan {
|
|||
0.0f,
|
||||
};
|
||||
device->fn.CmdSetBlendConstants(commands, blendConstants);
|
||||
|
||||
// The viewport and scissor default to cover all of the attachments
|
||||
VkViewport viewport;
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(info->GetWidth());
|
||||
viewport.height = static_cast<float>(info->GetHeight());
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
device->fn.CmdSetViewport(commands, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissorRect;
|
||||
scissorRect.offset.x = 0;
|
||||
scissorRect.offset.y = 0;
|
||||
scissorRect.extent.width = info->GetWidth();
|
||||
scissorRect.extent.height = info->GetHeight();
|
||||
device->fn.CmdSetScissor(commands, 0, 1, &scissorRect);
|
||||
|
||||
descriptorSets.OnBeginPass();
|
||||
} break;
|
||||
|
||||
case Command::DrawArrays: {
|
||||
|
@ -285,11 +266,6 @@ namespace backend { namespace vulkan {
|
|||
device->fn.CmdEndRenderPass(commands);
|
||||
} break;
|
||||
|
||||
case Command::EndRenderSubpass: {
|
||||
mCommands.NextCommand<EndRenderSubpassCmd>();
|
||||
// Do nothing because the single subpass is ended in vkEndRenderPass
|
||||
} break;
|
||||
|
||||
case Command::BeginComputePass: {
|
||||
mCommands.NextCommand<BeginComputePassCmd>();
|
||||
descriptorSets.OnBeginPass();
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
// Copyright 2018 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "backend/vulkan/FramebufferVk.h"
|
||||
|
||||
#include "backend/vulkan/FencedDeleter.h"
|
||||
#include "backend/vulkan/RenderPassVk.h"
|
||||
#include "backend/vulkan/TextureVk.h"
|
||||
#include "backend/vulkan/VulkanBackend.h"
|
||||
|
||||
namespace backend { namespace vulkan {
|
||||
|
||||
Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
|
||||
ASSERT(GetRenderPass()->GetAttachmentCount() <= kMaxColorAttachments + 1);
|
||||
|
||||
Device* device = ToBackend(GetDevice());
|
||||
|
||||
// Fill in the attachment info that will be chained in the create info.
|
||||
std::array<VkImageView, kMaxColorAttachments + 1> attachments;
|
||||
for (uint32_t i = 0; i < GetRenderPass()->GetAttachmentCount(); ++i) {
|
||||
attachments[i] = ToBackend(GetTextureView(i))->GetHandle();
|
||||
}
|
||||
|
||||
// Chain attachments and create the framebuffer
|
||||
VkFramebufferCreateInfo createInfo;
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.flags = 0;
|
||||
createInfo.renderPass = ToBackend(GetRenderPass())->GetHandle();
|
||||
createInfo.attachmentCount = GetRenderPass()->GetAttachmentCount();
|
||||
createInfo.pAttachments = attachments.data();
|
||||
createInfo.width = GetWidth();
|
||||
createInfo.height = GetHeight();
|
||||
createInfo.layers = 1;
|
||||
|
||||
if (device->fn.CreateFramebuffer(device->GetVkDevice(), &createInfo, nullptr, &mHandle) !=
|
||||
VK_SUCCESS) {
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
Framebuffer::~Framebuffer() {
|
||||
Device* device = ToBackend(GetDevice());
|
||||
|
||||
if (mHandle != VK_NULL_HANDLE) {
|
||||
device->GetFencedDeleter()->DeleteWhenUnused(mHandle);
|
||||
mHandle = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
VkFramebuffer Framebuffer::GetHandle() const {
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
void Framebuffer::FillClearValues(VkClearValue* values) {
|
||||
const RenderPassBase* renderPass = GetRenderPass();
|
||||
for (uint32_t i = 0; i < renderPass->GetAttachmentCount(); ++i) {
|
||||
if (TextureFormatHasDepthOrStencil(renderPass->GetAttachmentInfo(i).format)) {
|
||||
const auto& clearValues = GetClearDepthStencil(i);
|
||||
|
||||
values[i].depthStencil.depth = clearValues.depth;
|
||||
values[i].depthStencil.stencil = clearValues.stencil;
|
||||
} else {
|
||||
const auto& clearValues = GetClearColor(i);
|
||||
|
||||
values[i].color.float32[0] = clearValues.color[0];
|
||||
values[i].color.float32[1] = clearValues.color[1];
|
||||
values[i].color.float32[2] = clearValues.color[2];
|
||||
values[i].color.float32[3] = clearValues.color[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}} // namespace backend::vulkan
|
|
@ -19,10 +19,9 @@
|
|||
#include "backend/vulkan/CommandBufferVk.h"
|
||||
#include "backend/vulkan/ComputePipelineVk.h"
|
||||
#include "backend/vulkan/DepthStencilStateVk.h"
|
||||
#include "backend/vulkan/FramebufferVk.h"
|
||||
#include "backend/vulkan/InputStateVk.h"
|
||||
#include "backend/vulkan/PipelineLayoutVk.h"
|
||||
#include "backend/vulkan/RenderPassVk.h"
|
||||
#include "backend/vulkan/RenderPassInfoVk.h"
|
||||
#include "backend/vulkan/RenderPipelineVk.h"
|
||||
#include "backend/vulkan/SamplerVk.h"
|
||||
#include "backend/vulkan/ShaderModuleVk.h"
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
// Copyright 2018 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "backend/vulkan/RenderPassCache.h"
|
||||
|
||||
#include "backend/vulkan/TextureVk.h"
|
||||
#include "backend/vulkan/VulkanBackend.h"
|
||||
#include "common/BitSetIterator.h"
|
||||
#include "common/HashUtils.h"
|
||||
|
||||
namespace backend { namespace vulkan {
|
||||
|
||||
namespace {
|
||||
VkAttachmentLoadOp VulkanAttachmentLoadOp(nxt::LoadOp op) {
|
||||
switch (op) {
|
||||
case nxt::LoadOp::Load:
|
||||
return VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
case nxt::LoadOp::Clear:
|
||||
return VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
// RenderPassCacheQuery
|
||||
|
||||
void RenderPassCacheQuery::SetColor(uint32_t index,
|
||||
nxt::TextureFormat format,
|
||||
nxt::LoadOp loadOp) {
|
||||
colorMask.set(index);
|
||||
colorFormats[index] = format;
|
||||
colorLoadOp[index] = loadOp;
|
||||
}
|
||||
|
||||
void RenderPassCacheQuery::SetDepthStencil(nxt::TextureFormat format,
|
||||
nxt::LoadOp depthLoadOp,
|
||||
nxt::LoadOp stencilLoadOp) {
|
||||
hasDepthStencil = true;
|
||||
depthStencilFormat = format;
|
||||
this->depthLoadOp = depthLoadOp;
|
||||
this->stencilLoadOp = stencilLoadOp;
|
||||
}
|
||||
|
||||
// RenderPassCache
|
||||
|
||||
RenderPassCache::RenderPassCache(Device* device) : mDevice(device) {
|
||||
}
|
||||
|
||||
RenderPassCache::~RenderPassCache() {
|
||||
for (auto it : mCache) {
|
||||
mDevice->fn.DestroyRenderPass(mDevice->GetVkDevice(), it.second, nullptr);
|
||||
}
|
||||
mCache.clear();
|
||||
}
|
||||
|
||||
VkRenderPass RenderPassCache::GetRenderPass(const RenderPassCacheQuery& query) {
|
||||
auto it = mCache.find(query);
|
||||
if (it != mCache.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
VkRenderPass renderPass = CreateRenderPassForQuery(query);
|
||||
mCache.emplace(query, renderPass);
|
||||
return renderPass;
|
||||
}
|
||||
|
||||
VkRenderPass RenderPassCache::CreateRenderPassForQuery(
|
||||
const RenderPassCacheQuery& query) const {
|
||||
// The Vulkan subpasses want to know the layout of the attachments with VkAttachmentRef.
|
||||
// Precompute them as they must be pointer-chained in VkSubpassDescription
|
||||
std::array<VkAttachmentReference, kMaxColorAttachments + 1> attachmentRefs;
|
||||
|
||||
// Contains the attachment description that will be chained in the create info
|
||||
std::array<VkAttachmentDescription, kMaxColorAttachments + 1> attachmentDescs = {};
|
||||
|
||||
uint32_t attachmentCount = 0;
|
||||
for (uint32_t i : IterateBitSet(query.colorMask)) {
|
||||
auto& attachmentRef = attachmentRefs[attachmentCount];
|
||||
auto& attachmentDesc = attachmentDescs[attachmentCount];
|
||||
|
||||
attachmentRef.attachment = attachmentCount;
|
||||
attachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
attachmentDesc.flags = 0;
|
||||
attachmentDesc.format = VulkanImageFormat(query.colorFormats[i]);
|
||||
attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachmentDesc.loadOp = VulkanAttachmentLoadOp(query.colorLoadOp[i]);
|
||||
attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
attachmentCount++;
|
||||
}
|
||||
uint32_t colorAttachmentCount = attachmentCount;
|
||||
|
||||
VkAttachmentReference* depthStencilAttachment = nullptr;
|
||||
if (query.hasDepthStencil) {
|
||||
auto& attachmentRef = attachmentRefs[attachmentCount];
|
||||
auto& attachmentDesc = attachmentDescs[attachmentCount];
|
||||
|
||||
depthStencilAttachment = &attachmentRefs[attachmentCount];
|
||||
|
||||
attachmentRef.attachment = attachmentCount;
|
||||
attachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
attachmentDesc.flags = 0;
|
||||
attachmentDesc.format = VulkanImageFormat(query.depthStencilFormat);
|
||||
attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachmentDesc.loadOp = VulkanAttachmentLoadOp(query.depthLoadOp);
|
||||
attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachmentDesc.stencilLoadOp = VulkanAttachmentLoadOp(query.stencilLoadOp);
|
||||
attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
attachmentCount++;
|
||||
}
|
||||
|
||||
// Create the VkSubpassDescription that will be chained in the VkRenderPassCreateInfo
|
||||
VkSubpassDescription subpassDesc;
|
||||
subpassDesc.flags = 0;
|
||||
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpassDesc.inputAttachmentCount = 0;
|
||||
subpassDesc.pInputAttachments = nullptr;
|
||||
subpassDesc.colorAttachmentCount = colorAttachmentCount;
|
||||
subpassDesc.pColorAttachments = attachmentRefs.data();
|
||||
subpassDesc.pResolveAttachments = nullptr;
|
||||
subpassDesc.pDepthStencilAttachment = depthStencilAttachment;
|
||||
subpassDesc.preserveAttachmentCount = 0;
|
||||
subpassDesc.pPreserveAttachments = nullptr;
|
||||
|
||||
// Chain everything in VkRenderPassCreateInfo
|
||||
VkRenderPassCreateInfo createInfo;
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.flags = 0;
|
||||
createInfo.attachmentCount = attachmentCount;
|
||||
createInfo.pAttachments = attachmentDescs.data();
|
||||
createInfo.subpassCount = 1;
|
||||
createInfo.pSubpasses = &subpassDesc;
|
||||
createInfo.dependencyCount = 0;
|
||||
createInfo.pDependencies = nullptr;
|
||||
|
||||
// Create the render pass from the zillion parameters
|
||||
VkRenderPass renderPass;
|
||||
if (mDevice->fn.CreateRenderPass(mDevice->GetVkDevice(), &createInfo, nullptr,
|
||||
&renderPass) != VK_SUCCESS) {
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
return renderPass;
|
||||
}
|
||||
|
||||
// RenderPassCache
|
||||
|
||||
size_t RenderPassCache::CacheFuncs::operator()(const RenderPassCacheQuery& query) const {
|
||||
size_t hash = Hash(query.colorMask);
|
||||
|
||||
for (uint32_t i : IterateBitSet(query.colorMask)) {
|
||||
HashCombine(&hash, query.colorFormats[i], query.colorLoadOp[i]);
|
||||
}
|
||||
|
||||
HashCombine(&hash, query.hasDepthStencil);
|
||||
if (query.hasDepthStencil) {
|
||||
HashCombine(&hash, query.depthStencilFormat, query.depthLoadOp, query.stencilLoadOp);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
bool RenderPassCache::CacheFuncs::operator()(const RenderPassCacheQuery& a,
|
||||
const RenderPassCacheQuery& b) const {
|
||||
if (a.colorMask != b.colorMask) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (uint32_t i : IterateBitSet(a.colorMask)) {
|
||||
if ((a.colorFormats[i] != b.colorFormats[i]) ||
|
||||
(a.colorLoadOp[i] != b.colorLoadOp[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (a.hasDepthStencil != b.hasDepthStencil) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a.hasDepthStencil) {
|
||||
if ((a.depthStencilFormat != b.depthStencilFormat) ||
|
||||
(a.depthLoadOp != b.depthLoadOp) || (a.stencilLoadOp != b.stencilLoadOp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}} // namespace backend::vulkan
|
|
@ -0,0 +1,81 @@
|
|||
// Copyright 2018 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef BACKEND_VULKAN_RENDERPASSCACHE_H_
|
||||
#define BACKEND_VULKAN_RENDERPASSCACHE_H_
|
||||
|
||||
#include "common/vulkan_platform.h"
|
||||
|
||||
#include "common/Constants.h"
|
||||
#include "nxt/nxtcpp.h"
|
||||
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace backend { namespace vulkan {
|
||||
|
||||
class Device;
|
||||
|
||||
// This is a key to query the RenderPassCache, it can be sparse meaning that only the
|
||||
// information for bits set in colorMask or hasDepthStencil need to be provided and the rest can
|
||||
// be uninintialized.
|
||||
struct RenderPassCacheQuery {
|
||||
// Use these helpers to build the query, they make sure all relevant data is initialized and
|
||||
// masks set.
|
||||
void SetColor(uint32_t index, nxt::TextureFormat format, nxt::LoadOp loadOp);
|
||||
void SetDepthStencil(nxt::TextureFormat format,
|
||||
nxt::LoadOp depthLoadOp,
|
||||
nxt::LoadOp stencilLoadOp);
|
||||
|
||||
std::bitset<kMaxColorAttachments> colorMask;
|
||||
std::array<nxt::TextureFormat, kMaxColorAttachments> colorFormats;
|
||||
std::array<nxt::LoadOp, kMaxColorAttachments> colorLoadOp;
|
||||
|
||||
bool hasDepthStencil = false;
|
||||
nxt::TextureFormat depthStencilFormat;
|
||||
nxt::LoadOp depthLoadOp;
|
||||
nxt::LoadOp stencilLoadOp;
|
||||
};
|
||||
|
||||
// Caches VkRenderPasses so that we don't create duplicate ones for every RenderPipeline or
|
||||
// render pass.
|
||||
// TODO(cwallez@chromium.org): Make it an LRU cache somehow?
|
||||
class RenderPassCache {
|
||||
public:
|
||||
RenderPassCache(Device* device);
|
||||
~RenderPassCache();
|
||||
|
||||
VkRenderPass GetRenderPass(const RenderPassCacheQuery& query);
|
||||
|
||||
private:
|
||||
// Does the actual VkRenderPass creation on a cache miss.
|
||||
VkRenderPass CreateRenderPassForQuery(const RenderPassCacheQuery& query) const;
|
||||
|
||||
// Implements the functors necessary for to use RenderPassCacheQueries as unordered_map
|
||||
// keys.
|
||||
struct CacheFuncs {
|
||||
size_t operator()(const RenderPassCacheQuery& query) const;
|
||||
bool operator()(const RenderPassCacheQuery& a, const RenderPassCacheQuery& b) const;
|
||||
};
|
||||
using Cache =
|
||||
std::unordered_map<RenderPassCacheQuery, VkRenderPass, CacheFuncs, CacheFuncs>;
|
||||
|
||||
Device* mDevice = nullptr;
|
||||
Cache mCache;
|
||||
};
|
||||
|
||||
}} // namespace backend::vulkan
|
||||
|
||||
#endif // BACKEND_VULKAN_RENDERPASSCACHE_H_
|
|
@ -0,0 +1,122 @@
|
|||
// Copyright 2018 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "backend/vulkan/RenderPassInfoVk.h"
|
||||
|
||||
#include "backend/vulkan/FencedDeleter.h"
|
||||
#include "backend/vulkan/RenderPassCache.h"
|
||||
#include "backend/vulkan/TextureVk.h"
|
||||
#include "backend/vulkan/VulkanBackend.h"
|
||||
#include "common/BitSetIterator.h"
|
||||
|
||||
namespace backend { namespace vulkan {
|
||||
|
||||
RenderPassInfo::RenderPassInfo(RenderPassInfoBuilder* builder)
|
||||
: RenderPassInfoBase(builder), mDevice(ToBackend(builder->GetDevice())) {
|
||||
}
|
||||
|
||||
void RenderPassInfo::RecordBeginRenderPass(VkCommandBuffer commands) {
|
||||
// Query a VkRenderPass from the cache
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
{
|
||||
RenderPassCacheQuery query;
|
||||
|
||||
for (uint32_t i : IterateBitSet(GetColorAttachmentMask())) {
|
||||
const auto& attachmentInfo = GetColorAttachment(i);
|
||||
query.SetColor(i, attachmentInfo.view->GetTexture()->GetFormat(),
|
||||
attachmentInfo.loadOp);
|
||||
}
|
||||
|
||||
if (HasDepthStencilAttachment()) {
|
||||
const auto& attachmentInfo = GetDepthStencilAttachment();
|
||||
query.SetDepthStencil(attachmentInfo.view->GetTexture()->GetFormat(),
|
||||
attachmentInfo.depthLoadOp, attachmentInfo.stencilLoadOp);
|
||||
}
|
||||
|
||||
renderPass = mDevice->GetRenderPassCache()->GetRenderPass(query);
|
||||
}
|
||||
|
||||
// Create a framebuffer that will be used once for the render pass and gather the clear
|
||||
// values for the attachments at the same time.
|
||||
std::array<VkClearValue, kMaxColorAttachments + 1> clearValues;
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
uint32_t attachmentCount = 0;
|
||||
{
|
||||
// Fill in the attachment info that will be chained in the framebuffer create info.
|
||||
std::array<VkImageView, kMaxColorAttachments + 1> attachments;
|
||||
|
||||
for (uint32_t i : IterateBitSet(GetColorAttachmentMask())) {
|
||||
auto& attachmentInfo = GetColorAttachment(i);
|
||||
TextureView* view = ToBackend(attachmentInfo.view.Get());
|
||||
|
||||
attachments[attachmentCount] = view->GetHandle();
|
||||
|
||||
clearValues[attachmentCount].color.float32[0] = attachmentInfo.clearColor[0];
|
||||
clearValues[attachmentCount].color.float32[1] = attachmentInfo.clearColor[1];
|
||||
clearValues[attachmentCount].color.float32[2] = attachmentInfo.clearColor[2];
|
||||
clearValues[attachmentCount].color.float32[3] = attachmentInfo.clearColor[3];
|
||||
|
||||
attachmentCount++;
|
||||
}
|
||||
|
||||
if (HasDepthStencilAttachment()) {
|
||||
auto& attachmentInfo = GetDepthStencilAttachment();
|
||||
TextureView* view = ToBackend(attachmentInfo.view.Get());
|
||||
|
||||
attachments[attachmentCount] = view->GetHandle();
|
||||
|
||||
clearValues[attachmentCount].depthStencil.depth = attachmentInfo.clearDepth;
|
||||
clearValues[attachmentCount].depthStencil.stencil = attachmentInfo.clearStencil;
|
||||
|
||||
attachmentCount++;
|
||||
}
|
||||
|
||||
// Chain attachments and create the framebuffer
|
||||
VkFramebufferCreateInfo createInfo;
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.flags = 0;
|
||||
createInfo.renderPass = renderPass;
|
||||
createInfo.attachmentCount = attachmentCount;
|
||||
createInfo.pAttachments = attachments.data();
|
||||
createInfo.width = GetWidth();
|
||||
createInfo.height = GetHeight();
|
||||
createInfo.layers = 1;
|
||||
|
||||
if (mDevice->fn.CreateFramebuffer(mDevice->GetVkDevice(), &createInfo, nullptr,
|
||||
&framebuffer) != VK_SUCCESS) {
|
||||
ASSERT(false);
|
||||
}
|
||||
|
||||
// We don't reuse VkFramebuffers so mark the framebuffer for deletion as soon as the
|
||||
// commands currently being recorded are finished.
|
||||
mDevice->GetFencedDeleter()->DeleteWhenUnused(framebuffer);
|
||||
}
|
||||
|
||||
VkRenderPassBeginInfo beginInfo;
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
beginInfo.pNext = nullptr;
|
||||
beginInfo.renderPass = renderPass;
|
||||
beginInfo.framebuffer = framebuffer;
|
||||
beginInfo.renderArea.offset.x = 0;
|
||||
beginInfo.renderArea.offset.y = 0;
|
||||
beginInfo.renderArea.extent.width = GetWidth();
|
||||
beginInfo.renderArea.extent.height = GetHeight();
|
||||
beginInfo.clearValueCount = attachmentCount;
|
||||
beginInfo.pClearValues = clearValues.data();
|
||||
|
||||
mDevice->fn.CmdBeginRenderPass(commands, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
}
|
||||
|
||||
}} // namespace backend::vulkan
|
|
@ -12,27 +12,28 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef BACKEND_VULKAN_FRAMEBUFFERVK_H_
|
||||
#define BACKEND_VULKAN_FRAMEBUFFERVK_H_
|
||||
#ifndef BACKEND_VULKAN_RENDERPASSINFOVK_H_
|
||||
#define BACKEND_VULKAN_RENDERPASSINFOVK_H_
|
||||
|
||||
#include "backend/Framebuffer.h"
|
||||
#include "backend/RenderPassInfo.h"
|
||||
|
||||
#include "common/vulkan_platform.h"
|
||||
|
||||
namespace backend { namespace vulkan {
|
||||
|
||||
class Framebuffer : public FramebufferBase {
|
||||
public:
|
||||
Framebuffer(FramebufferBuilder* builder);
|
||||
~Framebuffer();
|
||||
class Device;
|
||||
|
||||
VkFramebuffer GetHandle() const;
|
||||
void FillClearValues(VkClearValue* values);
|
||||
class RenderPassInfo : public RenderPassInfoBase {
|
||||
public:
|
||||
RenderPassInfo(RenderPassInfoBuilder* builder);
|
||||
|
||||
// Compute all the arguments for, and record the vkCmdBeginRenderPass command.
|
||||
void RecordBeginRenderPass(VkCommandBuffer commands);
|
||||
|
||||
private:
|
||||
VkFramebuffer mHandle = VK_NULL_HANDLE;
|
||||
Device* mDevice = nullptr;
|
||||
};
|
||||
|
||||
}} // namespace backend::vulkan
|
||||
|
||||
#endif // BACKEND_VULKAN_FRAMEBUFFERVK_H_
|
||||
#endif // BACKEND_VULKAN_RENDERPASSINFOVK_H_
|
|
@ -1,133 +0,0 @@
|
|||
// Copyright 2018 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "backend/vulkan/RenderPassVk.h"
|
||||
|
||||
#include "backend/vulkan/FencedDeleter.h"
|
||||
#include "backend/vulkan/TextureVk.h"
|
||||
#include "backend/vulkan/VulkanBackend.h"
|
||||
#include "common/BitSetIterator.h"
|
||||
|
||||
namespace backend { namespace vulkan {
|
||||
|
||||
namespace {
|
||||
VkAttachmentLoadOp VulkanAttachmentLoadOp(nxt::LoadOp op) {
|
||||
switch (op) {
|
||||
case nxt::LoadOp::Load:
|
||||
return VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||
case nxt::LoadOp::Clear:
|
||||
return VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
RenderPass::RenderPass(RenderPassBuilder* builder)
|
||||
: RenderPassBase(builder), mDevice(ToBackend(builder->GetDevice())) {
|
||||
// For now we only support single pass render passes.
|
||||
ASSERT(GetSubpassCount() == 1);
|
||||
ASSERT(GetAttachmentCount() <= kMaxColorAttachments + 1);
|
||||
|
||||
const auto& subpass = GetSubpassInfo(0);
|
||||
|
||||
// The Vulkan subpasses want to know the layout of the attachments with VkAttachmentRef.
|
||||
// Precompute them as they must be pointer-chained in VkSubpassDescription
|
||||
std::array<VkAttachmentReference, kMaxColorAttachments + 1> attachmentRefs;
|
||||
attachmentRefs.fill(VkAttachmentReference{VK_ATTACHMENT_UNUSED, VK_IMAGE_LAYOUT_UNDEFINED});
|
||||
|
||||
for (uint32_t i : IterateBitSet(subpass.colorAttachmentsSet)) {
|
||||
attachmentRefs[i].attachment = subpass.colorAttachments[i];
|
||||
attachmentRefs[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
// TODO(cwallez@chromium.org): need validation rule that attachments are packed
|
||||
ASSERT(i == 0 || subpass.colorAttachmentsSet[i - 1]);
|
||||
}
|
||||
if (subpass.depthStencilAttachment) {
|
||||
attachmentRefs[kMaxColorAttachments].attachment = subpass.depthStencilAttachment;
|
||||
attachmentRefs[kMaxColorAttachments].layout =
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
|
||||
// Create the VkSubpassDescription that will be chained in the VkRenderPassCreateInfo
|
||||
VkSubpassDescription subpassDesc;
|
||||
subpassDesc.flags = 0;
|
||||
subpassDesc.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpassDesc.inputAttachmentCount = 0;
|
||||
subpassDesc.pInputAttachments = nullptr;
|
||||
subpassDesc.colorAttachmentCount =
|
||||
static_cast<uint32_t>(subpass.colorAttachmentsSet.count());
|
||||
subpassDesc.pColorAttachments = attachmentRefs.data();
|
||||
subpassDesc.pResolveAttachments = nullptr;
|
||||
subpassDesc.pDepthStencilAttachment = &attachmentRefs[kMaxColorAttachments];
|
||||
subpassDesc.preserveAttachmentCount = 0;
|
||||
subpassDesc.pPreserveAttachments = nullptr;
|
||||
|
||||
// Create the VkAttachmentDescriptions that will be chained in the VkRenderPassCreateInfo
|
||||
std::array<VkAttachmentDescription, kMaxColorAttachments + 1> attachmentDescs = {};
|
||||
for (uint32_t i = 0; i < GetAttachmentCount(); ++i) {
|
||||
const auto& attachment = GetAttachmentInfo(i);
|
||||
auto& attachmentDesc = attachmentDescs[i];
|
||||
|
||||
attachmentDesc.flags = 0;
|
||||
attachmentDesc.format = VulkanImageFormat(attachment.format);
|
||||
attachmentDesc.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
if (TextureFormatHasDepthOrStencil(attachment.format)) {
|
||||
attachmentDesc.loadOp = VulkanAttachmentLoadOp(attachment.depthLoadOp);
|
||||
attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachmentDesc.stencilLoadOp = VulkanAttachmentLoadOp(attachment.stencilLoadOp);
|
||||
attachmentDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
} else {
|
||||
attachmentDesc.loadOp = VulkanAttachmentLoadOp(attachment.colorLoadOp);
|
||||
attachmentDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
|
||||
attachmentDesc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
attachmentDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
}
|
||||
}
|
||||
|
||||
// Chain everything in VkRenderPassCreateInfo
|
||||
VkRenderPassCreateInfo createInfo;
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
createInfo.pNext = nullptr;
|
||||
createInfo.flags = 0;
|
||||
createInfo.attachmentCount = GetAttachmentCount();
|
||||
createInfo.pAttachments = attachmentDescs.data();
|
||||
createInfo.subpassCount = 1;
|
||||
createInfo.pSubpasses = &subpassDesc;
|
||||
createInfo.dependencyCount = 0;
|
||||
createInfo.pDependencies = nullptr;
|
||||
|
||||
// Create the render pass from the zillion parameters
|
||||
if (mDevice->fn.CreateRenderPass(mDevice->GetVkDevice(), &createInfo, nullptr, &mHandle) !=
|
||||
VK_SUCCESS) {
|
||||
ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
RenderPass::~RenderPass() {
|
||||
if (mHandle != VK_NULL_HANDLE) {
|
||||
mDevice->GetFencedDeleter()->DeleteWhenUnused(mHandle);
|
||||
mHandle = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
VkRenderPass RenderPass::GetHandle() const {
|
||||
return mHandle;
|
||||
}
|
||||
|
||||
}} // namespace backend::vulkan
|
|
@ -1,43 +0,0 @@
|
|||
// Copyright 2018 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef BACKEND_VULKAN_RENDERPASSVK_H_
|
||||
#define BACKEND_VULKAN_RENDERPASSVK_H_
|
||||
|
||||
#include "backend/RenderPass.h"
|
||||
|
||||
#include "common/vulkan_platform.h"
|
||||
|
||||
namespace backend { namespace vulkan {
|
||||
|
||||
class Device;
|
||||
|
||||
class RenderPass : public RenderPassBase {
|
||||
public:
|
||||
RenderPass(RenderPassBuilder* builder);
|
||||
~RenderPass();
|
||||
|
||||
// TODO(cwallez@chromium.org): We need a way to ask for a compatible VkRenderPass with the
|
||||
// given load an store operations. Also they should be cached. For now this is hardcoded to
|
||||
// have Load = Clear and Store = Write
|
||||
VkRenderPass GetHandle() const;
|
||||
|
||||
private:
|
||||
VkRenderPass mHandle = VK_NULL_HANDLE;
|
||||
Device* mDevice = nullptr;
|
||||
};
|
||||
|
||||
}} // namespace backend::vulkan
|
||||
|
||||
#endif // BACKEND_VULKAN_PIPELINELAYOUTVK_H_
|
|
@ -19,7 +19,8 @@
|
|||
#include "backend/vulkan/FencedDeleter.h"
|
||||
#include "backend/vulkan/InputStateVk.h"
|
||||
#include "backend/vulkan/PipelineLayoutVk.h"
|
||||
#include "backend/vulkan/RenderPassVk.h"
|
||||
#include "backend/vulkan/RenderPassCache.h"
|
||||
#include "backend/vulkan/RenderPassInfoVk.h"
|
||||
#include "backend/vulkan/ShaderModuleVk.h"
|
||||
#include "backend/vulkan/VulkanBackend.h"
|
||||
|
||||
|
@ -133,10 +134,8 @@ namespace backend { namespace vulkan {
|
|||
|
||||
// Initialize the "blend state info" that will be chained in the "create info" from the data
|
||||
// pre-computed in the BlendState
|
||||
const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(GetSubPass());
|
||||
|
||||
std::array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments;
|
||||
for (uint32_t i : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
||||
for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
|
||||
colorBlendAttachments[i] = ToBackend(GetBlendState(i))->GetState();
|
||||
}
|
||||
VkPipelineColorBlendStateCreateInfo colorBlend;
|
||||
|
@ -147,7 +146,7 @@ namespace backend { namespace vulkan {
|
|||
colorBlend.logicOpEnable = VK_FALSE;
|
||||
colorBlend.logicOp = VK_LOGIC_OP_CLEAR;
|
||||
// TODO(cwallez@chromium.org): Do we allow holes in the color attachments?
|
||||
colorBlend.attachmentCount = static_cast<uint32_t>(subpassInfo.colorAttachmentsSet.count());
|
||||
colorBlend.attachmentCount = static_cast<uint32_t>(GetColorAttachmentsMask().count());
|
||||
colorBlend.pAttachments = colorBlendAttachments.data();
|
||||
// The blend constant is always dynamic so we fill in a dummy value
|
||||
colorBlend.blendConstants[0] = 0.0f;
|
||||
|
@ -172,6 +171,24 @@ namespace backend { namespace vulkan {
|
|||
dynamic.dynamicStateCount = sizeof(dynamicStates) / sizeof(dynamicStates[0]);
|
||||
dynamic.pDynamicStates = dynamicStates;
|
||||
|
||||
// Get a VkRenderPass that matches the attachment formats for this pipeline, load ops don't
|
||||
// matter so set them all to LoadOp::Load
|
||||
VkRenderPass renderPass = VK_NULL_HANDLE;
|
||||
{
|
||||
RenderPassCacheQuery query;
|
||||
|
||||
for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
|
||||
query.SetColor(i, GetColorAttachmentFormat(i), nxt::LoadOp::Load);
|
||||
}
|
||||
|
||||
if (HasDepthStencilAttachment()) {
|
||||
query.SetDepthStencil(GetDepthStencilFormat(), nxt::LoadOp::Load,
|
||||
nxt::LoadOp::Load);
|
||||
}
|
||||
|
||||
renderPass = mDevice->GetRenderPassCache()->GetRenderPass(query);
|
||||
}
|
||||
|
||||
// The create info chains in a bunch of things created on the stack here or inside state
|
||||
// objects.
|
||||
VkGraphicsPipelineCreateInfo createInfo;
|
||||
|
@ -190,8 +207,8 @@ namespace backend { namespace vulkan {
|
|||
createInfo.pColorBlendState = &colorBlend;
|
||||
createInfo.pDynamicState = &dynamic;
|
||||
createInfo.layout = ToBackend(GetLayout())->GetHandle();
|
||||
createInfo.renderPass = ToBackend(GetRenderPass())->GetHandle();
|
||||
createInfo.subpass = GetSubPass();
|
||||
createInfo.renderPass = renderPass;
|
||||
createInfo.subpass = 0;
|
||||
createInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||
createInfo.basePipelineIndex = -1;
|
||||
|
||||
|
|
|
@ -24,11 +24,11 @@
|
|||
#include "backend/vulkan/ComputePipelineVk.h"
|
||||
#include "backend/vulkan/DepthStencilStateVk.h"
|
||||
#include "backend/vulkan/FencedDeleter.h"
|
||||
#include "backend/vulkan/FramebufferVk.h"
|
||||
#include "backend/vulkan/InputStateVk.h"
|
||||
#include "backend/vulkan/NativeSwapChainImplVk.h"
|
||||
#include "backend/vulkan/PipelineLayoutVk.h"
|
||||
#include "backend/vulkan/RenderPassVk.h"
|
||||
#include "backend/vulkan/RenderPassCache.h"
|
||||
#include "backend/vulkan/RenderPassInfoVk.h"
|
||||
#include "backend/vulkan/RenderPipelineVk.h"
|
||||
#include "backend/vulkan/SamplerVk.h"
|
||||
#include "backend/vulkan/ShaderModuleVk.h"
|
||||
|
@ -146,6 +146,7 @@ namespace backend { namespace vulkan {
|
|||
mDeleter = new FencedDeleter(this);
|
||||
mMapRequestTracker = new MapRequestTracker(this);
|
||||
mMemoryAllocator = new MemoryAllocator(this);
|
||||
mRenderPassCache = new RenderPassCache(this);
|
||||
}
|
||||
|
||||
Device::~Device() {
|
||||
|
@ -189,6 +190,11 @@ namespace backend { namespace vulkan {
|
|||
delete mMemoryAllocator;
|
||||
mMemoryAllocator = nullptr;
|
||||
|
||||
// The VkRenderPasses in the cache can be destroyed immediately since all commands referring
|
||||
// to them are guaranteed to be finished executing.
|
||||
delete mRenderPassCache;
|
||||
mRenderPassCache = nullptr;
|
||||
|
||||
// VkQueues are destroyed when the VkDevice is destroyed
|
||||
if (mVkDevice != VK_NULL_HANDLE) {
|
||||
fn.DestroyDevice(mVkDevice, nullptr);
|
||||
|
@ -231,9 +237,6 @@ namespace backend { namespace vulkan {
|
|||
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
|
||||
return new DepthStencilState(builder);
|
||||
}
|
||||
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
|
||||
return new Framebuffer(builder);
|
||||
}
|
||||
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
|
||||
return new InputState(builder);
|
||||
}
|
||||
|
@ -243,8 +246,8 @@ namespace backend { namespace vulkan {
|
|||
QueueBase* Device::CreateQueue(QueueBuilder* builder) {
|
||||
return new Queue(builder);
|
||||
}
|
||||
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) {
|
||||
return new RenderPass(builder);
|
||||
RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
|
||||
return new RenderPassInfo(builder);
|
||||
}
|
||||
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
|
||||
return new RenderPipeline(builder);
|
||||
|
@ -325,6 +328,10 @@ namespace backend { namespace vulkan {
|
|||
return mDeleter;
|
||||
}
|
||||
|
||||
RenderPassCache* Device::GetRenderPassCache() const {
|
||||
return mRenderPassCache;
|
||||
}
|
||||
|
||||
Serial Device::GetSerial() const {
|
||||
return mNextSerial;
|
||||
}
|
||||
|
|
|
@ -39,11 +39,10 @@ namespace backend { namespace vulkan {
|
|||
class ComputePipeline;
|
||||
class DepthStencilState;
|
||||
class Device;
|
||||
class Framebuffer;
|
||||
class InputState;
|
||||
class PipelineLayout;
|
||||
class Queue;
|
||||
class RenderPass;
|
||||
class RenderPassInfo;
|
||||
class RenderPipeline;
|
||||
class Sampler;
|
||||
class ShaderModule;
|
||||
|
@ -55,6 +54,7 @@ namespace backend { namespace vulkan {
|
|||
class FencedDeleter;
|
||||
class MapRequestTracker;
|
||||
class MemoryAllocator;
|
||||
class RenderPassCache;
|
||||
|
||||
struct VulkanBackendTraits {
|
||||
using BindGroupType = BindGroup;
|
||||
|
@ -66,11 +66,10 @@ namespace backend { namespace vulkan {
|
|||
using ComputePipelineType = ComputePipeline;
|
||||
using DepthStencilStateType = DepthStencilState;
|
||||
using DeviceType = Device;
|
||||
using FramebufferType = Framebuffer;
|
||||
using InputStateType = InputState;
|
||||
using PipelineLayoutType = PipelineLayout;
|
||||
using QueueType = Queue;
|
||||
using RenderPassType = RenderPass;
|
||||
using RenderPassInfoType = RenderPassInfo;
|
||||
using RenderPipelineType = RenderPipeline;
|
||||
using SamplerType = Sampler;
|
||||
using ShaderModuleType = ShaderModule;
|
||||
|
@ -103,6 +102,7 @@ namespace backend { namespace vulkan {
|
|||
FencedDeleter* GetFencedDeleter() const;
|
||||
MapRequestTracker* GetMapRequestTracker() const;
|
||||
MemoryAllocator* GetMemoryAllocator() const;
|
||||
RenderPassCache* GetRenderPassCache() const;
|
||||
|
||||
Serial GetSerial() const;
|
||||
|
||||
|
@ -119,11 +119,10 @@ namespace backend { namespace vulkan {
|
|||
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
|
||||
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
|
||||
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
|
||||
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
|
||||
InputStateBase* CreateInputState(InputStateBuilder* builder) override;
|
||||
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
|
||||
QueueBase* CreateQueue(QueueBuilder* builder) override;
|
||||
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override;
|
||||
RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
|
||||
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
|
||||
SamplerBase* CreateSampler(SamplerBuilder* builder) override;
|
||||
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
|
||||
|
@ -170,6 +169,7 @@ namespace backend { namespace vulkan {
|
|||
FencedDeleter* mDeleter = nullptr;
|
||||
MapRequestTracker* mMapRequestTracker = nullptr;
|
||||
MemoryAllocator* mMemoryAllocator = nullptr;
|
||||
RenderPassCache* mRenderPassCache = nullptr;
|
||||
|
||||
VkFence GetUnusedFence();
|
||||
void CheckPassedFences();
|
||||
|
|
|
@ -48,13 +48,12 @@ list(APPEND UNITTEST_SOURCES
|
|||
${VALIDATION_TESTS_DIR}/CopyCommandsValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/DepthStencilStateValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/DynamicStateCommandValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/FramebufferValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/InputStateValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/PushConstantsValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/VertexBufferValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/RenderPassValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/RenderPassInfoValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/RenderPipelineValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/UsageValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/VertexBufferValidationTests.cpp
|
||||
${VALIDATION_TESTS_DIR}/ValidationTest.cpp
|
||||
${VALIDATION_TESTS_DIR}/ValidationTest.h
|
||||
${TESTS_DIR}/UnittestsMain.cpp
|
||||
|
|
|
@ -45,7 +45,7 @@ class BlendStateTest : public NXTTest {
|
|||
.SetBindGroupLayout(0, bindGroupLayout)
|
||||
.GetResult();
|
||||
|
||||
fb = utils::CreateBasicFramebuffer(device, kRTSize, kRTSize);
|
||||
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
|
||||
}
|
||||
|
||||
struct TriangleSpec {
|
||||
|
@ -69,14 +69,14 @@ class BlendStateTest : public NXTTest {
|
|||
)");
|
||||
|
||||
basePipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(fb.renderPass, 0)
|
||||
.SetColorAttachmentFormat(0, renderPass.colorFormat)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.GetResult();
|
||||
|
||||
testPipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(fb.renderPass, 0)
|
||||
.SetColorAttachmentFormat(0, renderPass.colorFormat)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -112,29 +112,27 @@ class BlendStateTest : public NXTTest {
|
|||
|
||||
// Test that after drawing a triangle with the base color, and then the given triangle spec, the color is as expected
|
||||
void DoSingleSourceTest(RGBA8 base, const TriangleSpec& triangle, const RGBA8& expected) {
|
||||
fb.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
renderPass.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
// First use the base pipeline to draw a triangle with no blending
|
||||
.SetRenderPipeline(basePipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { base } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
// First use the base pipeline to draw a triangle with no blending
|
||||
.SetRenderPipeline(basePipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { base } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
|
||||
// Then use the test pipeline to draw the test triangle with blending
|
||||
.SetRenderPipeline(testPipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { triangle.color } })))
|
||||
.SetBlendColor(triangle.blendFactor[0], triangle.blendFactor[1], triangle.blendFactor[2], triangle.blendFactor[3])
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
// Then use the test pipeline to draw the test triangle with blending
|
||||
.SetRenderPipeline(testPipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { triangle.color } })))
|
||||
.SetBlendColor(triangle.blendFactor[0], triangle.blendFactor[1], triangle.blendFactor[2], triangle.blendFactor[3])
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected, fb.color, kRTSize / 2, kRTSize / 2);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected, renderPass.color, kRTSize / 2, kRTSize / 2);
|
||||
}
|
||||
|
||||
// Given a vector of tests where each element is <testColor, expectedColor>, check that all expectations are true for the given blend operation
|
||||
|
@ -175,7 +173,7 @@ class BlendStateTest : public NXTTest {
|
|||
CheckBlendFactor(base, nxt::BlendFactor::One, colorFactor, nxt::BlendFactor::One, alphaFactor, tests);
|
||||
}
|
||||
|
||||
utils::BasicFramebuffer fb;
|
||||
utils::BasicRenderPass renderPass;
|
||||
nxt::RenderPipeline basePipeline;
|
||||
nxt::RenderPipeline testPipeline;
|
||||
nxt::ShaderModule vsModule;
|
||||
|
@ -679,27 +677,25 @@ TEST_P(BlendStateTest, ColorWriteMaskBlendingDisabled) {
|
|||
RGBA8 base(32, 64, 128, 192);
|
||||
RGBA8 expected(32, 0, 0, 0);
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(testPipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { base } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected, fb.color, kRTSize / 2, kRTSize / 2);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected, renderPass.color, kRTSize / 2, kRTSize / 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Test that independent blend states on render targets works
|
||||
TEST_P(BlendStateTest, IndependentBlendState) {
|
||||
|
||||
std::array<nxt::Texture, 5> renderTargets;
|
||||
std::array<nxt::TextureView, 5> renderTargetViews;
|
||||
std::array<nxt::Texture, 4> renderTargets;
|
||||
std::array<nxt::TextureView, 4> renderTargetViews;
|
||||
|
||||
for (uint32_t i = 0; i < 5; ++i) {
|
||||
for (uint32_t i = 0; i < 4; ++i) {
|
||||
renderTargets[i] = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(kRTSize, kRTSize, 1)
|
||||
|
@ -711,30 +707,11 @@ TEST_P(BlendStateTest, IndependentBlendState) {
|
|||
renderTargetViews[i] = renderTargets[i].CreateTextureViewBuilder().GetResult();
|
||||
}
|
||||
|
||||
nxt::RenderPass renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(5)
|
||||
.SetSubpassCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetFormat(1, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetFormat(2, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetFormat(3, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetFormat(4, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
// Scatter these so we know indexing to the right shader location is working
|
||||
.SubpassSetColorAttachment(0, 0, 2)
|
||||
// We skip attachment index 1 to check the case where the blend states in the pipeline state are not tightly packed
|
||||
.SubpassSetColorAttachment(0, 1, 4)
|
||||
.SubpassSetColorAttachment(0, 2, 3)
|
||||
.SubpassSetColorAttachment(0, 3, 0)
|
||||
.GetResult();
|
||||
|
||||
nxt::Framebuffer framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(kRTSize, kRTSize)
|
||||
.SetAttachment(0, renderTargetViews[0])
|
||||
.SetAttachment(1, renderTargetViews[1])
|
||||
.SetAttachment(2, renderTargetViews[2])
|
||||
.SetAttachment(3, renderTargetViews[3])
|
||||
.SetAttachment(4, renderTargetViews[4])
|
||||
nxt::RenderPassInfo renderpass = device.CreateRenderPassInfoBuilder()
|
||||
.SetColorAttachment(0, renderTargetViews[0], nxt::LoadOp::Clear)
|
||||
.SetColorAttachment(1, renderTargetViews[1], nxt::LoadOp::Clear)
|
||||
.SetColorAttachment(2, renderTargetViews[2], nxt::LoadOp::Clear)
|
||||
.SetColorAttachment(3, renderTargetViews[3], nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
|
||||
nxt::ShaderModule fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
|
||||
|
@ -778,14 +755,20 @@ TEST_P(BlendStateTest, IndependentBlendState) {
|
|||
} };
|
||||
|
||||
basePipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetColorAttachmentFormat(1, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetColorAttachmentFormat(2, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetColorAttachmentFormat(3, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.GetResult();
|
||||
|
||||
testPipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetColorAttachmentFormat(1, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetColorAttachmentFormat(2, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetColorAttachmentFormat(3, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -808,73 +791,40 @@ TEST_P(BlendStateTest, IndependentBlendState) {
|
|||
RGBA8 expected2 = color2;
|
||||
RGBA8 expected3 = min(color3, base);
|
||||
|
||||
renderTargets[2].TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
renderTargets[4].TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
renderTargets[3].TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
renderTargets[0].TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
renderTargets[1].TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
renderTargets[2].TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
renderTargets[3].TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(basePipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 4>({ { base, base, base, base } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.BeginRenderPass(renderpass)
|
||||
.SetRenderPipeline(basePipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 4>({ { base, base, base, base } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
|
||||
.SetRenderPipeline(testPipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 4>({ { color0, color1, color2, color3 } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.SetRenderPipeline(testPipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 4>({ { color0, color1, color2, color3 } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected0, renderTargets[2], kRTSize / 2, kRTSize / 2) << "Attachment slot 0 using render target 2 should have been " << color0 << " + " << base << " = " << expected0;
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected1, renderTargets[4], kRTSize / 2, kRTSize / 2) << "Attachment slot 1 using render target 4 should have been " << color1 << " - " << base << " = " << expected1;
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected2, renderTargets[3], kRTSize / 2, kRTSize / 2) << "Attachment slot 2 using render target 3 should have been " << color2 << " = " << expected2 << "(no blending)";
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected3, renderTargets[0], kRTSize / 2, kRTSize / 2) << "Attachment slot 3 using render target 0 should have been min(" << color3 << ", " << base << ") = " << expected3;
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected0, renderTargets[0], kRTSize / 2, kRTSize / 2) << "Attachment slot 0 should have been " << color0 << " + " << base << " = " << expected0;
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected1, renderTargets[1], kRTSize / 2, kRTSize / 2) << "Attachment slot 1 should have been " << color1 << " - " << base << " = " << expected1;
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected2, renderTargets[2], kRTSize / 2, kRTSize / 2) << "Attachment slot 2 should have been " << color2 << " = " << expected2 << "(no blending)";
|
||||
EXPECT_PIXEL_RGBA8_EQ(expected3, renderTargets[3], kRTSize / 2, kRTSize / 2) << "Attachment slot 3 should have been min(" << color3 << ", " << base << ") = " << expected3;
|
||||
}
|
||||
}
|
||||
|
||||
// Test that the default blend color is correctly set at the beginning of every subpass
|
||||
TEST_P(BlendStateTest, DefaultBlendColor) {
|
||||
if (IsVulkan()) {
|
||||
std::cout << "Test skipped on Vulkan because it doesn't support multisubpass renderpasses"
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
nxt::BlendState blendState = device.CreateBlendStateBuilder()
|
||||
.SetBlendEnabled(true)
|
||||
.SetColorBlend(nxt::BlendOperation::Add, nxt::BlendFactor::BlendColor, nxt::BlendFactor::One)
|
||||
.SetAlphaBlend(nxt::BlendOperation::Add, nxt::BlendFactor::BlendColor, nxt::BlendFactor::One)
|
||||
.GetResult();
|
||||
|
||||
nxt::RenderPass renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.SetSubpassCount(2)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.SubpassSetColorAttachment(1, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
nxt::Texture renderTarget = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(kRTSize, kRTSize, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment | nxt::TextureUsageBit::TransferSrc)
|
||||
.SetInitialUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
|
||||
nxt::TextureView renderTargetView = renderTarget.CreateTextureViewBuilder().GetResult();
|
||||
|
||||
nxt::Framebuffer framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(kRTSize, kRTSize)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.GetResult();
|
||||
|
||||
nxt::ShaderModule fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
|
||||
#version 450
|
||||
layout(set = 0, binding = 0) uniform myBlock {
|
||||
|
@ -889,29 +839,14 @@ TEST_P(BlendStateTest, DefaultBlendColor) {
|
|||
)");
|
||||
|
||||
basePipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, renderPass.colorFormat)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.GetResult();
|
||||
|
||||
testPipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetColorAttachmentBlendState(0, blendState)
|
||||
.GetResult();
|
||||
|
||||
nxt::RenderPipeline basePipeline2 = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 1)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.GetResult();
|
||||
|
||||
nxt::RenderPipeline testPipeline2 = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 1)
|
||||
.SetColorAttachmentFormat(0, renderPass.colorFormat)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -921,28 +856,25 @@ TEST_P(BlendStateTest, DefaultBlendColor) {
|
|||
// Check that the initial blend color is (0,0,0,0)
|
||||
{
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(basePipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.SetRenderPipeline(testPipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderTarget, kRTSize / 2, kRTSize / 2);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, kRTSize / 2, kRTSize / 2);
|
||||
}
|
||||
|
||||
// Check that setting the blend color works
|
||||
{
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(basePipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
|
@ -950,20 +882,18 @@ TEST_P(BlendStateTest, DefaultBlendColor) {
|
|||
.SetBlendColor(1, 1, 1, 1)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(255, 255, 255, 255), renderTarget, kRTSize / 2, kRTSize / 2);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(255, 255, 255, 255), renderPass.color, kRTSize / 2, kRTSize / 2);
|
||||
}
|
||||
|
||||
// Check that the blend color is not inherited
|
||||
// Check that the blend color is not inherited between render passes
|
||||
{
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(basePipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
|
@ -971,21 +901,20 @@ TEST_P(BlendStateTest, DefaultBlendColor) {
|
|||
.SetBlendColor(1, 1, 1, 1)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(basePipeline2)
|
||||
.EndRenderPass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(basePipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.SetRenderPipeline(testPipeline2)
|
||||
.SetRenderPipeline(testPipeline)
|
||||
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } })))
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderTarget, kRTSize / 2, kRTSize / 2);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, kRTSize / 2, kRTSize / 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,17 +24,6 @@ class DepthStencilStateTest : public NXTTest {
|
|||
void SetUp() override {
|
||||
NXTTest::SetUp();
|
||||
|
||||
renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(2)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.AttachmentSetFormat(1, nxt::TextureFormat::D32FloatS8Uint)
|
||||
.AttachmentSetDepthStencilLoadOps(1, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.SubpassSetDepthStencilAttachment(0, 1)
|
||||
.GetResult();
|
||||
|
||||
renderTarget = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(kRTSize, kRTSize, 1)
|
||||
|
@ -57,11 +46,9 @@ class DepthStencilStateTest : public NXTTest {
|
|||
|
||||
depthTextureView = depthTexture.CreateTextureViewBuilder().GetResult();
|
||||
|
||||
framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.SetAttachment(1, depthTextureView)
|
||||
.SetDimensions(kRTSize, kRTSize)
|
||||
renderpass = device.CreateRenderPassInfoBuilder()
|
||||
.SetColorAttachment(0, renderTargetView, nxt::LoadOp::Clear)
|
||||
.SetDepthStencilAttachment(depthTextureView, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
|
||||
vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||
|
@ -207,8 +194,7 @@ class DepthStencilStateTest : public NXTTest {
|
|||
};
|
||||
|
||||
renderTarget.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
builder.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass();
|
||||
builder.BeginRenderPass(renderpass);
|
||||
|
||||
for (size_t i = 0; i < testParams.size(); ++i) {
|
||||
const TestSpec& test = testParams[i];
|
||||
|
@ -233,7 +219,8 @@ class DepthStencilStateTest : public NXTTest {
|
|||
|
||||
// Create a pipeline for the triangles with the test spec's depth stencil state
|
||||
nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -247,7 +234,6 @@ class DepthStencilStateTest : public NXTTest {
|
|||
}
|
||||
|
||||
nxt::CommandBuffer commands = builder
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
@ -261,12 +247,11 @@ class DepthStencilStateTest : public NXTTest {
|
|||
DoTest(testParams, expected, expected);
|
||||
}
|
||||
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::RenderPassInfo renderpass;
|
||||
nxt::Texture renderTarget;
|
||||
nxt::Texture depthTexture;
|
||||
nxt::TextureView renderTargetView;
|
||||
nxt::TextureView depthTextureView;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::ShaderModule vsModule;
|
||||
nxt::ShaderModule fsModule;
|
||||
nxt::BindGroupLayout bindGroupLayout;
|
||||
|
|
|
@ -23,30 +23,7 @@ class DrawElementsTest : public NXTTest {
|
|||
void SetUp() override {
|
||||
NXTTest::SetUp();
|
||||
|
||||
renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
renderTarget = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(kRTSize, kRTSize, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment | nxt::TextureUsageBit::TransferSrc)
|
||||
.SetInitialUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
|
||||
renderTargetView = renderTarget.CreateTextureViewBuilder().GetResult();
|
||||
|
||||
framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.SetDimensions(kRTSize, kRTSize)
|
||||
.GetResult();
|
||||
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
|
||||
|
||||
nxt::InputState inputState = device.CreateInputStateBuilder()
|
||||
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
|
||||
|
@ -70,7 +47,7 @@ class DrawElementsTest : public NXTTest {
|
|||
);
|
||||
|
||||
pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, renderPass.colorFormat)
|
||||
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleStrip)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -89,10 +66,7 @@ class DrawElementsTest : public NXTTest {
|
|||
});
|
||||
}
|
||||
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Texture renderTarget;
|
||||
nxt::TextureView renderTargetView;
|
||||
nxt::Framebuffer framebuffer;
|
||||
utils::BasicRenderPass renderPass;
|
||||
nxt::RenderPipeline pipeline;
|
||||
nxt::Buffer vertexBuffer;
|
||||
nxt::Buffer indexBuffer;
|
||||
|
@ -101,20 +75,18 @@ class DrawElementsTest : public NXTTest {
|
|||
uint32_t firstInstance, RGBA8 bottomLeftExpected, RGBA8 topRightExpected) {
|
||||
uint32_t zeroOffset = 0;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
|
||||
.SetIndexBuffer(indexBuffer, 0)
|
||||
.DrawElements(indexCount, instanceCount, firstIndex, firstInstance)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(bottomLeftExpected, renderTarget, 1, 3);
|
||||
EXPECT_PIXEL_RGBA8_EQ(topRightExpected, renderTarget, 3, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(bottomLeftExpected, renderPass.color, 1, 3);
|
||||
EXPECT_PIXEL_RGBA8_EQ(topRightExpected, renderPass.color, 3, 1);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -24,36 +24,10 @@ class IndexFormatTest : public NXTTest {
|
|||
void SetUp() override {
|
||||
NXTTest::SetUp();
|
||||
|
||||
renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
renderTarget = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(kRTSize, kRTSize, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment | nxt::TextureUsageBit::TransferSrc)
|
||||
.SetInitialUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
|
||||
renderTargetView = renderTarget.CreateTextureViewBuilder().GetResult();
|
||||
|
||||
framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.SetDimensions(kRTSize, kRTSize)
|
||||
.GetResult();
|
||||
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
|
||||
}
|
||||
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Texture renderTarget;
|
||||
nxt::TextureView renderTargetView;
|
||||
nxt::Framebuffer framebuffer;
|
||||
utils::BasicRenderPass renderPass;
|
||||
|
||||
nxt::RenderPipeline MakeTestPipeline(nxt::IndexFormat format) {
|
||||
nxt::InputState inputState = device.CreateInputStateBuilder()
|
||||
|
@ -78,7 +52,7 @@ class IndexFormatTest : public NXTTest {
|
|||
);
|
||||
|
||||
return device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, renderPass.colorFormat)
|
||||
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleStrip)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -105,19 +79,17 @@ TEST_P(IndexFormatTest, Uint32) {
|
|||
|
||||
uint32_t zeroOffset = 0;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
|
||||
.SetIndexBuffer(indexBuffer, 0)
|
||||
.DrawElements(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderTarget, 100, 300);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 100, 300);
|
||||
}
|
||||
|
||||
// Test that the Uint16 index format is correctly interpreted
|
||||
|
@ -136,19 +108,17 @@ TEST_P(IndexFormatTest, Uint16) {
|
|||
|
||||
uint32_t zeroOffset = 0;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
|
||||
.SetIndexBuffer(indexBuffer, 0)
|
||||
.DrawElements(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderTarget, 100, 300);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 100, 300);
|
||||
}
|
||||
|
||||
// Test for primitive restart use vertices like in the drawing and draw the following
|
||||
|
@ -180,21 +150,19 @@ TEST_P(IndexFormatTest, Uint32PrimitiveRestart) {
|
|||
|
||||
uint32_t zeroOffset = 0;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
|
||||
.SetIndexBuffer(indexBuffer, 0)
|
||||
.DrawElements(7, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderTarget, 190, 190); // A
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderTarget, 210, 210); // B
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderTarget, 210, 190); // C
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 190, 190); // A
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 210, 210); // B
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, 210, 190); // C
|
||||
}
|
||||
|
||||
// Test use of primitive restart with an Uint16 index format
|
||||
|
@ -214,21 +182,19 @@ TEST_P(IndexFormatTest, Uint16PrimitiveRestart) {
|
|||
|
||||
uint32_t zeroOffset = 0;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
|
||||
.SetIndexBuffer(indexBuffer, 0)
|
||||
.DrawElements(7, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderTarget, 190, 190); // A
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderTarget, 210, 210); // B
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderTarget, 210, 190); // C
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 190, 190); // A
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 210, 210); // B
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, 210, 190); // C
|
||||
}
|
||||
|
||||
// Test that the index format used is the format of the last set pipeline. This is to
|
||||
|
@ -256,20 +222,18 @@ TEST_P(IndexFormatTest, ChangePipelineAfterSetIndexBuffer) {
|
|||
|
||||
uint32_t zeroOffset = 0;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline16)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
|
||||
.SetIndexBuffer(indexBuffer, 0)
|
||||
.SetRenderPipeline(pipeline32)
|
||||
.DrawElements(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderTarget, 100, 300);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 100, 300);
|
||||
}
|
||||
|
||||
// Test that setting the index buffer before the pipeline works, this is important
|
||||
|
@ -291,19 +255,17 @@ TEST_P(IndexFormatTest, DISABLED_SetIndexBufferBeforeSetPipeline) {
|
|||
|
||||
uint32_t zeroOffset = 0;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetIndexBuffer(indexBuffer, 0)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
|
||||
.DrawElements(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderTarget, 100, 300);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 100, 300);
|
||||
}
|
||||
|
||||
NXT_INSTANTIATE_TEST(IndexFormatTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)
|
||||
|
|
|
@ -37,7 +37,7 @@ class InputStateTest : public NXTTest {
|
|||
void SetUp() override {
|
||||
NXTTest::SetUp();
|
||||
|
||||
fb = utils::CreateBasicFramebuffer(device, kRTSize, kRTSize);
|
||||
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
|
||||
}
|
||||
|
||||
bool ShouldComponentBeDefault(VertexFormat format, int component) {
|
||||
|
@ -121,7 +121,7 @@ class InputStateTest : public NXTTest {
|
|||
);
|
||||
|
||||
return device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(fb.renderPass, 0)
|
||||
.SetColorAttachmentFormat(0, renderPass.colorFormat)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
|
@ -168,9 +168,8 @@ class InputStateTest : public NXTTest {
|
|||
|
||||
nxt::CommandBufferBuilder builder = device.CreateCommandBufferBuilder();
|
||||
|
||||
fb.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
builder.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
renderPass.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
builder.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline);
|
||||
|
||||
uint32_t zeroOffset = 0;
|
||||
|
@ -180,7 +179,6 @@ class InputStateTest : public NXTTest {
|
|||
|
||||
nxt::CommandBuffer commands = builder
|
||||
.DrawArrays(triangles * 3, instances, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
@ -193,15 +191,15 @@ class InputStateTest : public NXTTest {
|
|||
unsigned int x = kRTCellOffset + kRTCellSize * triangle;
|
||||
unsigned int y = kRTCellOffset + kRTCellSize * instance;
|
||||
if (triangle < triangles && instance < instances) {
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, x, y);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, x, y);
|
||||
} else {
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), fb.color, x, y);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
utils::BasicFramebuffer fb;
|
||||
utils::BasicRenderPass renderPass;
|
||||
};
|
||||
|
||||
// Test compilation and usage of the fixture :)
|
||||
|
|
|
@ -147,30 +147,7 @@ class PrimitiveTopologyTest : public NXTTest {
|
|||
void SetUp() override {
|
||||
NXTTest::SetUp();
|
||||
|
||||
renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
renderTarget = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(kRTSize, kRTSize, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment | nxt::TextureUsageBit::TransferSrc)
|
||||
.SetInitialUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
|
||||
renderTargetView = renderTarget.CreateTextureViewBuilder().GetResult();
|
||||
|
||||
framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.SetDimensions(kRTSize, kRTSize)
|
||||
.GetResult();
|
||||
renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
|
||||
|
||||
vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
|
@ -209,22 +186,20 @@ class PrimitiveTopologyTest : public NXTTest {
|
|||
// Draw the vertices with the given primitive topology and check the pixel values of the test locations
|
||||
void DoTest(nxt::PrimitiveTopology primitiveTopology, const std::vector<LocationSpec> &locationSpecs) {
|
||||
nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, renderPass.colorFormat)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
.SetPrimitiveTopology(primitiveTopology)
|
||||
.GetResult();
|
||||
|
||||
renderTarget.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
renderPass.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
static const uint32_t zeroOffset = 0;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
|
||||
.DrawArrays(6, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
@ -234,16 +209,13 @@ class PrimitiveTopologyTest : public NXTTest {
|
|||
for (size_t i = 0; i < locationSpec.count; ++i) {
|
||||
// If this pixel is included, check that it is green. Otherwise, check that it is black
|
||||
RGBA8 color = locationSpec.include ? RGBA8(0, 255, 0, 255) : RGBA8(0, 0, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(color, renderTarget, locationSpec.locations[i].x, locationSpec.locations[i].y)
|
||||
EXPECT_PIXEL_RGBA8_EQ(color, renderPass.color, locationSpec.locations[i].x, locationSpec.locations[i].y)
|
||||
<< "Expected (" << locationSpec.locations[i].x << ", " << locationSpec.locations[i].y << ") to be " << color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Texture renderTarget;
|
||||
nxt::TextureView renderTargetView;
|
||||
nxt::Framebuffer framebuffer;
|
||||
utils::BasicRenderPass renderPass;
|
||||
nxt::ShaderModule vsModule;
|
||||
nxt::ShaderModule fsModule;
|
||||
nxt::InputState inputState;
|
||||
|
|
|
@ -160,8 +160,7 @@ class PushConstantTest: public NXTTest {
|
|||
|
||||
// The render pipeline adds one to the red channel for successful vertex push constant test
|
||||
// and adds one to green for the frgament test.
|
||||
nxt::RenderPipeline MakeTestRenderPipeline(nxt::PipelineLayout& layout, nxt::RenderPass& renderPass, uint32_t subpass,
|
||||
PushConstantSpec vsSpec, PushConstantSpec fsSpec) {
|
||||
nxt::RenderPipeline MakeTestRenderPipeline(nxt::PipelineLayout& layout, PushConstantSpec vsSpec, PushConstantSpec fsSpec) {
|
||||
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, (R"(
|
||||
#version 450
|
||||
)" + MakePushConstantBlock(vsSpec) + R"(
|
||||
|
@ -192,7 +191,7 @@ class PushConstantTest: public NXTTest {
|
|||
.GetResult();
|
||||
|
||||
return device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderPass, subpass)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(layout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -233,63 +232,26 @@ TEST_P(PushConstantTest, ComputePassDefaultsToZero) {
|
|||
EXPECT_BUFFER_U32_EQ(1, binding.resultBuffer, 0);
|
||||
}
|
||||
|
||||
// Test that push constants default to zero at the beginning of every render subpasses.
|
||||
TEST_P(PushConstantTest, RenderSubpassDefaultsToZero) {
|
||||
// Change the renderpass to be a two subpass renderpass just for this test.
|
||||
nxt::RenderPass renderPass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.SetSubpassCount(2)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.SubpassSetColorAttachment(1, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
nxt::Texture renderTarget = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(1, 1, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment | nxt::TextureUsageBit::TransferSrc)
|
||||
.SetInitialUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
|
||||
nxt::TextureView renderTargetView = renderTarget.CreateTextureViewBuilder().GetResult();
|
||||
|
||||
nxt::Framebuffer framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderPass)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.SetDimensions(1, 1)
|
||||
.GetResult();
|
||||
// Test that push constants default to zero at the beginning of render passes.
|
||||
TEST_P(PushConstantTest, RenderPassDefaultsToZero) {
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
|
||||
|
||||
// Expect push constants to be zero in all draws of this test.
|
||||
PushConstantSpec allZeros = MakeAllZeroSpec();
|
||||
nxt::PipelineLayout layout = MakeEmptyLayout();
|
||||
nxt::RenderPipeline pipeline1 = MakeTestRenderPipeline(layout, renderPass, 0, MakeAllZeroSpec(), MakeAllZeroSpec());
|
||||
nxt::RenderPipeline pipeline2 = MakeTestRenderPipeline(layout, renderPass, 1, MakeAllZeroSpec(), MakeAllZeroSpec());
|
||||
nxt::RenderPipeline pipeline = MakeTestRenderPipeline(layout, MakeAllZeroSpec(), MakeAllZeroSpec());
|
||||
|
||||
uint32_t notZero = 42;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderPass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
// Test render push constants are set to zero by default.
|
||||
.SetRenderPipeline(pipeline1)
|
||||
.DrawArrays(1, 1, 0, 0)
|
||||
// Set push constants to non-zero value to check they will be reset to zero
|
||||
// on the next subpass. This tests both fragment and vertex as they write to different
|
||||
// color channels on error.
|
||||
.SetPushConstants(nxt::ShaderStageBit::Fragment | nxt::ShaderStageBit::Vertex, 0, 1, ¬Zero)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(pipeline2)
|
||||
.DrawArrays(1, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
// Test render push constants are set to zero by default.
|
||||
.SetRenderPipeline(pipeline)
|
||||
.DrawArrays(1, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(2, 2, 0, 0), renderTarget, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 1, 0, 0), renderPass.color, 0, 0);
|
||||
}
|
||||
|
||||
// Test setting push constants of various 32bit types.
|
||||
|
@ -389,51 +351,47 @@ TEST_P(PushConstantTest, SeparateVertexAndFragmentConstants) {
|
|||
PushConstantSpec vsSpec = {{Int, 1}};
|
||||
PushConstantSpec fsSpec = {{Int, 2}};
|
||||
|
||||
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 1, 1);
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
|
||||
|
||||
nxt::PipelineLayout layout = MakeEmptyLayout();
|
||||
nxt::RenderPipeline pipeline = MakeTestRenderPipeline(layout, fb.renderPass, 0, vsSpec, fsSpec);
|
||||
nxt::RenderPipeline pipeline = MakeTestRenderPipeline(layout, vsSpec, fsSpec);
|
||||
|
||||
uint32_t one = 1;
|
||||
uint32_t two = 2;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, &one)
|
||||
.SetPushConstants(nxt::ShaderStageBit::Fragment, 0, 1, &two)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.DrawArrays(1, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, &one)
|
||||
.SetPushConstants(nxt::ShaderStageBit::Fragment, 0, 1, &two)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.DrawArrays(1, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 1, 0, 0), fb.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 1, 0, 0), renderPass.color, 0, 0);
|
||||
}
|
||||
|
||||
// Try setting push constants for vertex and fragment stage simulteanously
|
||||
TEST_P(PushConstantTest, SimultaneousVertexAndFragmentConstants) {
|
||||
PushConstantSpec spec = {{Int, 2}};
|
||||
|
||||
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 1, 1);
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
|
||||
|
||||
nxt::PipelineLayout layout = MakeEmptyLayout();
|
||||
nxt::RenderPipeline pipeline = MakeTestRenderPipeline(layout, fb.renderPass, 0, spec, spec);
|
||||
nxt::RenderPipeline pipeline = MakeTestRenderPipeline(layout, spec, spec);
|
||||
|
||||
uint32_t two = 2;
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, &two)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.DrawArrays(1, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, &two)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.DrawArrays(1, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 1, 0, 0), fb.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(1, 1, 0, 0), renderPass.color, 0, 0);
|
||||
}
|
||||
NXT_INSTANTIATE_TEST(PushConstantTest, MetalBackend, OpenGLBackend)
|
||||
|
|
|
@ -32,9 +32,9 @@ class DrawQuad {
|
|||
.GetResult();
|
||||
}
|
||||
|
||||
void Draw(const nxt::RenderPass& renderpass, nxt::CommandBufferBuilder* builder) {
|
||||
void Draw(nxt::CommandBufferBuilder* builder) {
|
||||
auto renderPipeline = device->CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -108,127 +108,63 @@ class RenderPassLoadOpTests : public NXTTest {
|
|||
|
||||
// Tests clearing, loading, and drawing into color attachments
|
||||
TEST_P(RenderPassLoadOpTests, ColorClearThenLoadAndDraw) {
|
||||
if (IsOpenGL()) {
|
||||
// TODO(kainino@chromium.org): currently fails on OpenGL backend
|
||||
return;
|
||||
}
|
||||
|
||||
// Part 1: clear once, check to make sure it's cleared
|
||||
|
||||
auto renderpass1 = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.SetSubpassCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
auto framebuffer1 = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass1)
|
||||
.SetDimensions(kRTSize, kRTSize)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
auto renderPassClearZero = device.CreateRenderPassInfoBuilder()
|
||||
.SetColorAttachment(0, renderTargetView, nxt::LoadOp::Clear)
|
||||
.SetColorAttachmentClearColor(0, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.GetResult();
|
||||
|
||||
auto commands1 = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass1, framebuffer1)
|
||||
.BeginRenderSubpass()
|
||||
auto commandsClearZero = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderPassClearZero)
|
||||
// Clear should occur implicitly
|
||||
// Store should occur implicitly
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
framebuffer1.AttachmentSetClearColor(0, 0.0f, 0.0f, 0.0f, 0.0f); // zero
|
||||
queue.Submit(1, &commands1);
|
||||
// Cleared to zero
|
||||
auto renderPassClearGreen = device.CreateRenderPassInfoBuilder()
|
||||
.SetColorAttachment(0, renderTargetView, nxt::LoadOp::Clear)
|
||||
.SetColorAttachmentClearColor(0, 0.0f, 1.0f, 0.0f, 1.0f)
|
||||
.GetResult();
|
||||
|
||||
auto commandsClearGreen = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderPassClearGreen)
|
||||
// Clear should occur implicitly
|
||||
// Store should occur implicitly
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commandsClearZero);
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expectZero.data(), renderTarget, 0, 0, kRTSize, kRTSize, 0);
|
||||
|
||||
framebuffer1.AttachmentSetClearColor(0, 0.0f, 1.0f, 0.0f, 1.0f); // green
|
||||
queue.Submit(1, &commands1);
|
||||
// Now cleared to green
|
||||
queue.Submit(1, &commandsClearGreen);
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize, kRTSize, 0);
|
||||
|
||||
// Part 2: draw a blue quad into the right half of the render target, and check result
|
||||
|
||||
auto renderpass2 = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.SetSubpassCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Load)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
auto renderPassLoad = device.CreateRenderPassInfoBuilder()
|
||||
.SetColorAttachment(0, renderTargetView, nxt::LoadOp::Load)
|
||||
.GetResult();
|
||||
auto framebuffer2 = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass2)
|
||||
.SetDimensions(kRTSize, kRTSize)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.GetResult();
|
||||
framebuffer2.AttachmentSetClearColor(0, 1.0f, 0.0f, 0.0f, 1.0f); // red
|
||||
|
||||
nxt::CommandBuffer commands2;
|
||||
nxt::CommandBuffer commandsLoad;
|
||||
{
|
||||
auto builder = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass2, framebuffer2)
|
||||
.BeginRenderSubpass()
|
||||
// Clear should occur implicitly
|
||||
.BeginRenderPass(renderPassLoad)
|
||||
// Load should occur implicitly
|
||||
.Clone();
|
||||
blueQuad.Draw(renderpass2, &builder);
|
||||
commands2 = builder
|
||||
blueQuad.Draw(&builder);
|
||||
commandsLoad = builder
|
||||
// Store should occur implicitly
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
queue.Submit(1, &commands2);
|
||||
queue.Submit(1, &commandsLoad);
|
||||
// Left half should still be green
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize / 2, kRTSize, 0);
|
||||
// Right half should now be blue
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expectBlue.data(), renderTarget, kRTSize / 2, 0, kRTSize / 2, kRTSize, 0);
|
||||
}
|
||||
|
||||
// Tests that an attachment is cleared only on the first subpass that uses it in a renderpass
|
||||
TEST_P(RenderPassLoadOpTests, ClearsOnlyOnFirstUsePerRenderPass) {
|
||||
if (IsOpenGL()) {
|
||||
// TODO(kainino@chromium.org): currently fails on OpenGL backend
|
||||
return;
|
||||
}
|
||||
|
||||
auto renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.SetSubpassCount(2)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.SubpassSetColorAttachment(1, 0, 0)
|
||||
.GetResult();
|
||||
auto framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(kRTSize, kRTSize)
|
||||
.SetAttachment(0, renderTargetView)
|
||||
.GetResult();
|
||||
|
||||
nxt::CommandBuffer commands;
|
||||
auto builder = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
// Clear should occur implicitly
|
||||
.Clone();
|
||||
blueQuad.Draw(renderpass, &builder);
|
||||
commands = builder
|
||||
// Store should occur implicitly
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderSubpass()
|
||||
// Load (not clear!) should occur implicitly
|
||||
// Store should occur implicitly
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
framebuffer.AttachmentSetClearColor(0, 0.0f, 1.0f, 0.0f, 1.0f); // green
|
||||
queue.Submit(1, &commands);
|
||||
// Left half should still be green from the first clear
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize / 2, kRTSize, 0);
|
||||
// Right half should be blue, not cleared by the second subpass
|
||||
EXPECT_TEXTURE_RGBA8_EQ(expectBlue.data(), renderTarget, kRTSize / 2, 0, kRTSize / 2, kRTSize, 0);
|
||||
}
|
||||
|
||||
NXT_INSTANTIATE_TEST(RenderPassLoadOpTests, D3D12Backend, MetalBackend, OpenGLBackend)
|
||||
|
|
|
@ -40,8 +40,8 @@ class SamplerTest : public NXTTest {
|
|||
protected:
|
||||
void SetUp() override {
|
||||
NXTTest::SetUp();
|
||||
mFB = utils::CreateBasicFramebuffer(device, kRTSize, kRTSize);
|
||||
mFB.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
mRenderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
|
||||
mRenderPass.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
|
||||
mBindGroupLayout = device.CreateBindGroupLayoutBuilder()
|
||||
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler, 0, 1)
|
||||
|
@ -76,7 +76,7 @@ protected:
|
|||
)");
|
||||
|
||||
mPipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(mFB.renderPass, 0)
|
||||
.SetColorAttachmentFormat(0, mRenderPass.colorFormat)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -123,12 +123,10 @@ protected:
|
|||
.GetResult();
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(mFB.renderPass, mFB.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(mRenderPass.renderPassInfo)
|
||||
.SetRenderPipeline(mPipeline)
|
||||
.SetBindGroup(0, bindGroup)
|
||||
.DrawArrays(6, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
@ -140,18 +138,18 @@ protected:
|
|||
RGBA8 expectedV3(v.mExpected3, v.mExpected3, v.mExpected3, 255);
|
||||
RGBA8 black(0, 0, 0, 255);
|
||||
RGBA8 white(255, 255, 255, 255);
|
||||
EXPECT_PIXEL_RGBA8_EQ(black, mFB.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(white, mFB.color, 0, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(white, mFB.color, 1, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(black, mFB.color, 1, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expectedU2, mFB.color, 2, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expectedU3, mFB.color, 3, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expectedV2, mFB.color, 0, 2);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expectedV3, mFB.color, 0, 3);
|
||||
EXPECT_PIXEL_RGBA8_EQ(black, mRenderPass.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(white, mRenderPass.color, 0, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(white, mRenderPass.color, 1, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(black, mRenderPass.color, 1, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expectedU2, mRenderPass.color, 2, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expectedU3, mRenderPass.color, 3, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expectedV2, mRenderPass.color, 0, 2);
|
||||
EXPECT_PIXEL_RGBA8_EQ(expectedV3, mRenderPass.color, 0, 3);
|
||||
// TODO: add tests for W address mode, once NXT supports 3D textures
|
||||
}
|
||||
|
||||
utils::BasicFramebuffer mFB;
|
||||
utils::BasicRenderPass mRenderPass;
|
||||
nxt::BindGroupLayout mBindGroupLayout;
|
||||
nxt::RenderPipeline mPipeline;
|
||||
nxt::TextureView mTextureView;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
class ScissorTest: public NXTTest {
|
||||
protected:
|
||||
nxt::RenderPipeline CreateQuadPipeline(const nxt::RenderPass& renderPass) {
|
||||
nxt::RenderPipeline CreateQuadPipeline(nxt::TextureFormat format) {
|
||||
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
const vec2 pos[6] = vec2[6](
|
||||
|
@ -37,7 +37,7 @@ class ScissorTest: public NXTTest {
|
|||
})");
|
||||
|
||||
nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderPass, 0)
|
||||
.SetColorAttachmentFormat(0, format)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.GetResult();
|
||||
|
@ -48,47 +48,43 @@ class ScissorTest: public NXTTest {
|
|||
|
||||
// Test that by default the scissor test is disabled and the whole attachment can be drawn to.
|
||||
TEST_P(ScissorTest, DefaultsToWholeRenderTarget) {
|
||||
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 100, 100);
|
||||
nxt::RenderPipeline pipeline = CreateQuadPipeline(fb.renderPass);
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 100, 100);
|
||||
nxt::RenderPipeline pipeline = CreateQuadPipeline(renderPass.colorFormat);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.DrawArrays(6, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 0, 99);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 99, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 99, 99);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 0, 99);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 99, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 99, 99);
|
||||
}
|
||||
|
||||
// Test setting the scissor to something larger than the attachments.
|
||||
TEST_P(ScissorTest, LargerThanAttachment) {
|
||||
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 100, 100);
|
||||
nxt::RenderPipeline pipeline = CreateQuadPipeline(fb.renderPass);
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 100, 100);
|
||||
nxt::RenderPipeline pipeline = CreateQuadPipeline(renderPass.colorFormat);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetScissorRect(0, 0, 200, 200)
|
||||
.DrawArrays(6, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 0, 99);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 99, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 99, 99);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 0, 99);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 99, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 99, 99);
|
||||
}
|
||||
|
||||
// Test setting an empty scissor rect
|
||||
|
@ -98,86 +94,76 @@ TEST_P(ScissorTest, EmptyRect) {
|
|||
return;
|
||||
}
|
||||
|
||||
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 2, 2);
|
||||
nxt::RenderPipeline pipeline = CreateQuadPipeline(fb.renderPass);
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 2, 2);
|
||||
nxt::RenderPipeline pipeline = CreateQuadPipeline(renderPass.colorFormat);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetScissorRect(0, 0, 0, 0)
|
||||
.DrawArrays(6, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), fb.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), fb.color, 0, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), fb.color, 1, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), fb.color, 1, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, 0, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, 1, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, 1, 1);
|
||||
}
|
||||
|
||||
// Test setting a partial scissor (not empty, not full attachment)
|
||||
TEST_P(ScissorTest, PartialRect) {
|
||||
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 100, 100);
|
||||
nxt::RenderPipeline pipeline = CreateQuadPipeline(fb.renderPass);
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 100, 100);
|
||||
nxt::RenderPipeline pipeline = CreateQuadPipeline(renderPass.colorFormat);
|
||||
|
||||
constexpr uint32_t kX = 3;
|
||||
constexpr uint32_t kY = 7;
|
||||
constexpr uint32_t kW = 5;
|
||||
constexpr uint32_t kH = 13;
|
||||
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.SetScissorRect(kX, kY, kW, kH)
|
||||
.DrawArrays(6, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
// Test the two opposite corners of the scissor box. With one pixel inside and on outside
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), fb.color, kX - 1, kY - 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, kX, kY);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, kX - 1, kY - 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, kX, kY);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), fb.color, kX + kW, kY + kH);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, kX + kW - 1, kY + kH - 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, kX + kW, kY + kH);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, kX + kW - 1, kY + kH - 1);
|
||||
}
|
||||
|
||||
// Test that the scissor setting doesn't get inherited between renderpasses
|
||||
// TODO(cwallez@chromium.org): do the same between subpasses?
|
||||
TEST_P(ScissorTest, NoInheritanceBetweenRenderPass) {
|
||||
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 100, 100);
|
||||
nxt::RenderPipeline pipeline = CreateQuadPipeline(fb.renderPass);
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 100, 100);
|
||||
nxt::RenderPipeline pipeline = CreateQuadPipeline(renderPass.colorFormat);
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
// RenderPass 1 set the scissor
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetScissorRect(0, 0, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
// RenderPass 2 draw a full quad, it shouldn't be scissored
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.DrawArrays(6, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 0, 99);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 99, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 99, 99);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 0, 99);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 99, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 99, 99);
|
||||
}
|
||||
|
||||
NXT_INSTANTIATE_TEST(ScissorTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)
|
||||
|
|
|
@ -20,7 +20,7 @@ class ViewportOrientationTests : public NXTTest {};
|
|||
|
||||
// Test that the pixel in viewport coordinate (-1, -1) matches texel (0, 0)
|
||||
TEST_P(ViewportOrientationTests, OriginAt0x0) {
|
||||
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 2, 2);
|
||||
utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 2, 2);
|
||||
|
||||
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
|
||||
#version 450
|
||||
|
@ -36,27 +36,25 @@ TEST_P(ViewportOrientationTests, OriginAt0x0) {
|
|||
})");
|
||||
|
||||
nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(fb.renderPass, 0)
|
||||
.SetColorAttachmentFormat(0, renderPass.colorFormat)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetPrimitiveTopology(nxt::PrimitiveTopology::PointList)
|
||||
.GetResult();
|
||||
|
||||
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
|
||||
.BeginRenderPass(fb.renderPass, fb.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPassInfo)
|
||||
.SetRenderPipeline(pipeline)
|
||||
.DrawArrays(1, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
queue.Submit(1, &commands);
|
||||
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), fb.color, 0, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), fb.color, 1, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), fb.color, 1, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 0, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, 0, 1);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, 1, 0);
|
||||
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, 1, 1);
|
||||
}
|
||||
|
||||
NXT_INSTANTIATE_TEST(ViewportOrientationTests, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)
|
||||
|
|
|
@ -23,43 +23,15 @@ TEST_F(CommandBufferValidationTest, Empty) {
|
|||
.GetResult();
|
||||
}
|
||||
|
||||
// Tests for null arguments to the command buffer builder
|
||||
TEST_F(CommandBufferValidationTest, NullArguments) {
|
||||
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(0)
|
||||
.GetResult();
|
||||
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(100, 100)
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpass, nullptr)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(nullptr, framebuffer)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Tests for basic render pass usage
|
||||
TEST_F(CommandBufferValidationTest, RenderPass) {
|
||||
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetAttachmentCount(0)
|
||||
.SetSubpassCount(1)
|
||||
.GetResult();
|
||||
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(100, 100)
|
||||
.GetResult();
|
||||
auto renderpass = CreateSimpleRenderPass();
|
||||
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderPass(renderpass)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderPass(renderpass)
|
||||
.GetResult();
|
||||
}
|
||||
|
|
|
@ -17,23 +17,13 @@
|
|||
class SetScissorRectTest : public ValidationTest {
|
||||
};
|
||||
|
||||
// Test to check that SetScissor can only be used inside render subpasses
|
||||
TEST_F(SetScissorRectTest, AllowedOnlyInRenderSubpass) {
|
||||
// Test to check that SetScissor can only be used inside render passes
|
||||
TEST_F(SetScissorRectTest, AllowedOnlyInRenderPass) {
|
||||
DummyRenderPass renderPass = CreateDummyRenderPass();
|
||||
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPass)
|
||||
.SetScissorRect(0, 0, 1, 1)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
|
||||
.SetScissorRect(0, 0, 1, 1)
|
||||
.BeginRenderSubpass()
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
@ -53,10 +43,8 @@ TEST_F(SetScissorRectTest, EmptyScissor) {
|
|||
DummyRenderPass renderPass = CreateDummyRenderPass();
|
||||
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPass)
|
||||
.SetScissorRect(0, 0, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
@ -68,10 +56,8 @@ TEST_F(SetScissorRectTest, ScissorLargerThanFramebuffer) {
|
|||
DummyRenderPass renderPass = CreateDummyRenderPass();
|
||||
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPass)
|
||||
.SetScissorRect(0, 0, renderPass.width + 1, renderPass.height + 1)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
@ -79,23 +65,13 @@ TEST_F(SetScissorRectTest, ScissorLargerThanFramebuffer) {
|
|||
class SetBlendColorTest : public ValidationTest {
|
||||
};
|
||||
|
||||
// Test to check that SetBlendColor can only be used inside render subpasses
|
||||
TEST_F(SetBlendColorTest, AllowedOnlyInRenderSubpass) {
|
||||
// Test to check that SetBlendColor can only be used inside render passes
|
||||
TEST_F(SetBlendColorTest, AllowedOnlyInRenderPass) {
|
||||
DummyRenderPass renderPass = CreateDummyRenderPass();
|
||||
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPass)
|
||||
.SetBlendColor(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
|
||||
.SetBlendColor(0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.BeginRenderSubpass()
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
@ -115,10 +91,8 @@ TEST_F(SetBlendColorTest, AnyValueAllowed) {
|
|||
DummyRenderPass renderPass = CreateDummyRenderPass();
|
||||
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPass)
|
||||
.SetBlendColor(-1.0f, 42.0f, -0.0f, 0.0f)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
@ -126,23 +100,13 @@ TEST_F(SetBlendColorTest, AnyValueAllowed) {
|
|||
class SetStencilReferenceTest : public ValidationTest {
|
||||
};
|
||||
|
||||
// Test to check that SetStencilReference can only be used inside render subpasses
|
||||
TEST_F(SetStencilReferenceTest, AllowedOnlyInRenderSubpass) {
|
||||
// Test to check that SetStencilReference can only be used inside render passes
|
||||
TEST_F(SetStencilReferenceTest, AllowedOnlyInRenderPass) {
|
||||
DummyRenderPass renderPass = CreateDummyRenderPass();
|
||||
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPass)
|
||||
.SetStencilReference(0)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
|
||||
.SetStencilReference(0)
|
||||
.BeginRenderSubpass()
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
|
@ -162,10 +126,8 @@ TEST_F(SetStencilReferenceTest, AllBitsAllowed) {
|
|||
DummyRenderPass renderPass = CreateDummyRenderPass();
|
||||
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderPass.renderPass)
|
||||
.SetStencilReference(0xFFFFFFFF)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
|
|
@ -1,227 +0,0 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
|
||||
class FramebufferValidationTest : public ValidationTest {
|
||||
protected:
|
||||
nxt::TextureView Create2DAttachment(uint32_t width, uint32_t height, nxt::TextureFormat format) {
|
||||
nxt::Texture attachment = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(width, height, 1)
|
||||
.SetFormat(format)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.SetInitialUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
|
||||
return attachment.CreateTextureViewBuilder()
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
nxt::Framebuffer CreateFramebufferWithAttachment(uint32_t width, uint32_t height, nxt::TextureFormat format) {
|
||||
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, format)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
nxt::TextureView attachment = Create2DAttachment(width, height, format);
|
||||
return AssertWillBeSuccess(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, attachment)
|
||||
.SetDimensions(100, 100)
|
||||
.GetResult();
|
||||
}
|
||||
};
|
||||
|
||||
// Test for an empty framebuffer builder
|
||||
TEST_F(FramebufferValidationTest, Empty) {
|
||||
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Tests for null arguments to a framebuffer builder
|
||||
TEST_F(FramebufferValidationTest, NullArguments) {
|
||||
AssertWillBeError(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(nullptr)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Tests for passing error-valued arguments to a framebuffer builder
|
||||
TEST_F(FramebufferValidationTest, ErrorValues) {
|
||||
auto renderpass = AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.GetResult();
|
||||
AssertWillBeError(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Tests for basic framebuffer construction
|
||||
TEST_F(FramebufferValidationTest, Basic) {
|
||||
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(0)
|
||||
.GetResult();
|
||||
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(100, 100)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Tests for framebuffer construction with an (empty) attachment
|
||||
TEST_F(FramebufferValidationTest, BasicWithEmptyAttachment) {
|
||||
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
AssertWillBeError(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(100, 100)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Test for a basic framebuffer with one attachment
|
||||
TEST_F(FramebufferValidationTest, BasicWithOneAttachment) {
|
||||
CreateFramebufferWithAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
}
|
||||
|
||||
// Tests for setting clear values
|
||||
TEST_F(FramebufferValidationTest, ClearValues) {
|
||||
auto framebuffer = CreateFramebufferWithAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
|
||||
// Set clear color value for attachment 0
|
||||
framebuffer.AttachmentSetClearColor(0, 0.0f, 0.0f, 0.0f, 0.0f);
|
||||
// Set clear depth/stencil values for attachment 0 - ok, but ignored, since it's a color attachment
|
||||
framebuffer.AttachmentSetClearDepthStencil(0, 0.0f, 0);
|
||||
// Set clear color value for attachment 1 - should fail
|
||||
ASSERT_DEVICE_ERROR(framebuffer.AttachmentSetClearColor(1, 0.0f, 0.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
// Check validation that the attachment size must be the same as the framebuffer size.
|
||||
// TODO(cwallez@chromium.org): Investigate this constraint more, for example Vulkan requires
|
||||
// that the attachment sizes are *at least* the framebuffer size.
|
||||
TEST_F(FramebufferValidationTest, AttachmentSizeMatchFramebufferSize) {
|
||||
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
nxt::TextureView attachment = Create2DAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
|
||||
// Control case: two attachments of the same size
|
||||
{
|
||||
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, attachment)
|
||||
.SetDimensions(100, 100)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Error: case, size mismatch (framebuffer bigger than attachments)
|
||||
{
|
||||
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, attachment)
|
||||
.SetDimensions(200, 200)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Error: case, size mismatch (framebuffer smaller than attachments)
|
||||
{
|
||||
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, attachment)
|
||||
.SetDimensions(50, 50)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// TODO(cwallez@chromium.org): also test with a mismatches depth / stencil
|
||||
}
|
||||
|
||||
TEST_F(FramebufferValidationTest, AttachmentFormatMatchTextureFormat) {
|
||||
// Control case: attach color attachment to color slot
|
||||
{
|
||||
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
nxt::TextureView attachment = Create2DAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, attachment)
|
||||
.SetDimensions(100, 100)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Error: attach color attachment to depth slot, setting the attachment format first
|
||||
{
|
||||
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetAttachmentCount(1)
|
||||
.SetSubpassCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SubpassSetDepthStencilAttachment(0, 0)
|
||||
.GetResult();
|
||||
|
||||
nxt::TextureView attachment = Create2DAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, attachment)
|
||||
.SetDimensions(100, 100)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Error: attach color attachment to depth slot, but setting the attachment format last
|
||||
{
|
||||
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.SubpassSetDepthStencilAttachment(0, 0)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::D32FloatS8Uint)
|
||||
.GetResult();
|
||||
|
||||
nxt::TextureView attachment = Create2DAttachment(100, 100, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, attachment)
|
||||
.SetDimensions(100, 100)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Error: attach depth texture to color slot
|
||||
{
|
||||
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
nxt::TextureView attachment = Create2DAttachment(100, 100, nxt::TextureFormat::D32FloatS8Uint);
|
||||
auto framebuffer = AssertWillBeError(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(renderpass)
|
||||
.SetAttachment(0, attachment)
|
||||
.SetDimensions(100, 100)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// TODO(kainino@chromium.org): also check attachment samples, etc.
|
||||
}
|
|
@ -46,7 +46,7 @@ class InputStateTest : public ValidationTest {
|
|||
builder = AssertWillBeError(device.CreateRenderPipelineBuilder());
|
||||
}
|
||||
|
||||
return builder.SetSubpass(renderpassData.renderPass, 0)
|
||||
return builder.SetColorAttachmentFormat(0, renderpassData.attachmentFormat)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
|
|
|
@ -54,11 +54,9 @@ TEST_F(PushConstantTest, Success) {
|
|||
.SetPushConstants(nxt::ShaderStageBit::Compute, 0, 1, constants)
|
||||
.EndComputePass()
|
||||
|
||||
// PushConstants in a render subpass
|
||||
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
// PushConstants in a render pass
|
||||
.BeginRenderPass(renderpassData.renderPass)
|
||||
.SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, constants)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
|
||||
// Setting all constants
|
||||
|
@ -120,36 +118,9 @@ TEST_F(PushConstantTest, NotInPass) {
|
|||
.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, constants)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Setting in renderpass but outside subpass is invalid
|
||||
{
|
||||
// Control to check the error is caused by the SetPushConstants
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
|
||||
.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, constants)
|
||||
.BeginRenderSubpass()
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.EndRenderSubpass()
|
||||
.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, constants)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
// Test valid stages for subpass
|
||||
// Test valid stages for compute pass
|
||||
TEST_F(PushConstantTest, StageForComputePass) {
|
||||
// Control case: setting to the compute stage in compute passes
|
||||
{
|
||||
|
@ -179,17 +150,15 @@ TEST_F(PushConstantTest, StageForComputePass) {
|
|||
}
|
||||
}
|
||||
|
||||
// Test valid stages for compute passes
|
||||
TEST_F(PushConstantTest, StageForSubpass) {
|
||||
// Test valid stages for render passes
|
||||
TEST_F(PushConstantTest, StageForRenderPass) {
|
||||
DummyRenderPass renderpassData = CreateDummyRenderPass();
|
||||
|
||||
// Control case: setting to vertex and fragment in subpass
|
||||
// Control case: setting to vertex and fragment in render pass
|
||||
{
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderpassData.renderPass)
|
||||
.SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, constants)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
@ -197,10 +166,8 @@ TEST_F(PushConstantTest, StageForSubpass) {
|
|||
// Compute stage is disallowed
|
||||
{
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderpassData.renderPass)
|
||||
.SetPushConstants(nxt::ShaderStageBit::Compute, 0, 1, constants)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
@ -208,10 +175,8 @@ TEST_F(PushConstantTest, StageForSubpass) {
|
|||
// A None shader stage mask is valid.
|
||||
{
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.BeginRenderPass(renderpassData.renderPass)
|
||||
.SetPushConstants(nxt::ShaderStageBit::None, 0, 1, constants)
|
||||
.EndRenderSubpass()
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,181 @@
|
|||
// Copyright 2018 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
|
||||
#include "common/Constants.h"
|
||||
|
||||
namespace {
|
||||
|
||||
class RenderPassInfoValidationTest : public ValidationTest {
|
||||
};
|
||||
|
||||
nxt::TextureView Create2DAttachment(nxt::Device& device, uint32_t width, uint32_t height, nxt::TextureFormat format) {
|
||||
nxt::Texture attachment = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(width, height, 1)
|
||||
.SetFormat(format)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.SetInitialUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
|
||||
return attachment.CreateTextureViewBuilder()
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// A render pass with no attachments isn't valid
|
||||
TEST_F(RenderPassInfoValidationTest, Empty) {
|
||||
AssertWillBeError(device.CreateRenderPassInfoBuilder())
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// A render pass with only one color or one depth attachment is ok
|
||||
TEST_F(RenderPassInfoValidationTest, OneAttachment) {
|
||||
// One color attachment
|
||||
{
|
||||
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(0, color, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
// One depth-stencil attachment
|
||||
{
|
||||
nxt::TextureView depthStencil = Create2DAttachment(device, 1, 1, nxt::TextureFormat::D32FloatS8Uint);
|
||||
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
|
||||
.SetDepthStencilAttachment(depthStencil, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
// Test OOB color attachment indices are handled
|
||||
TEST_F(RenderPassInfoValidationTest, ColorAttachmentOutOfBounds) {
|
||||
// For setting the color attachment, control case
|
||||
{
|
||||
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(kMaxColorAttachments - 1, color, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
// For setting the color attachment, OOB
|
||||
{
|
||||
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
AssertWillBeError(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(kMaxColorAttachments, color, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
// For setting the clear color, control case
|
||||
{
|
||||
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(0, color, nxt::LoadOp::Clear)
|
||||
.SetColorAttachmentClearColor(kMaxColorAttachments - 1, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.GetResult();
|
||||
}
|
||||
// For setting the clear color, OOB
|
||||
{
|
||||
AssertWillBeError(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(0, color, nxt::LoadOp::Clear)
|
||||
.SetColorAttachmentClearColor(kMaxColorAttachments, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
// Test setting a clear value without an attachment and vice-versa is ok.
|
||||
TEST_F(RenderPassInfoValidationTest, ClearAndAttachmentMismatchIsOk) {
|
||||
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
|
||||
// For cleared attachment 0 doesn't get a color, clear color for 1 is unused
|
||||
{
|
||||
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(0, color, nxt::LoadOp::Clear)
|
||||
.SetColorAttachmentClearColor(1, 0.0f, 0.0f, 0.0f, 0.0f)
|
||||
.GetResult();
|
||||
}
|
||||
// Clear depth stencil doesn't get values
|
||||
{
|
||||
nxt::TextureView depthStencil = Create2DAttachment(device, 1, 1, nxt::TextureFormat::D32FloatS8Uint);
|
||||
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
|
||||
.SetDepthStencilAttachment(depthStencil, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
// Clear values for depth-stencil when it isn't used
|
||||
{
|
||||
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(0, color, nxt::LoadOp::Clear)
|
||||
.SetDepthStencilAttachmentClearValue(0.0f, 0)
|
||||
.GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
// Attachments must have the same size
|
||||
TEST_F(RenderPassInfoValidationTest, SizeMustMatch) {
|
||||
nxt::TextureView color1x1A = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
nxt::TextureView color1x1B = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
nxt::TextureView color2x2 = Create2DAttachment(device, 2, 2, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
nxt::TextureView depthStencil1x1 = Create2DAttachment(device, 1, 1, nxt::TextureFormat::D32FloatS8Uint);
|
||||
nxt::TextureView depthStencil2x2 = Create2DAttachment(device, 2, 2, nxt::TextureFormat::D32FloatS8Uint);
|
||||
|
||||
// Control case: all the same size (1x1)
|
||||
{
|
||||
AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(0, color1x1A, nxt::LoadOp::Clear)
|
||||
.SetColorAttachment(1, color1x1B, nxt::LoadOp::Clear)
|
||||
.SetDepthStencilAttachment(depthStencil1x1, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// One of the color attachments has a different size
|
||||
{
|
||||
AssertWillBeError(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(0, color1x1A, nxt::LoadOp::Clear)
|
||||
.SetColorAttachment(1, color2x2, nxt::LoadOp::Clear)
|
||||
.SetDepthStencilAttachment(depthStencil1x1, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// The depth stencil attachment has a different size
|
||||
{
|
||||
AssertWillBeError(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(0, color1x1A, nxt::LoadOp::Clear)
|
||||
.SetColorAttachment(1, color1x1B, nxt::LoadOp::Clear)
|
||||
.SetDepthStencilAttachment(depthStencil2x2, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
// Attachments formats must match whether they are used for color or depth-stencil
|
||||
TEST_F(RenderPassInfoValidationTest, FormatMismatch) {
|
||||
nxt::TextureView color = Create2DAttachment(device, 1, 1, nxt::TextureFormat::R8G8B8A8Unorm);
|
||||
nxt::TextureView depthStencil = Create2DAttachment(device, 1, 1, nxt::TextureFormat::D32FloatS8Uint);
|
||||
|
||||
// Using depth-stencil for color
|
||||
{
|
||||
AssertWillBeError(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(0, depthStencil, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Using color for depth-stencil
|
||||
{
|
||||
AssertWillBeError(device.CreateRenderPassInfoBuilder())
|
||||
.SetDepthStencilAttachment(color, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(cwallez@chromium.org): Constraints on attachment aliasing?
|
||||
|
||||
} // anonymous namespace
|
|
@ -1,159 +0,0 @@
|
|||
// Copyright 2017 The NXT Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
|
||||
class RenderPassValidationTest : public ValidationTest {
|
||||
};
|
||||
|
||||
// Test for an empty render pass builder
|
||||
TEST_F(RenderPassValidationTest, Empty) {
|
||||
AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Test for a render pass with one subpass and no attachments
|
||||
TEST_F(RenderPassValidationTest, OneSubpass) {
|
||||
AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(0)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Test for a render pass with one subpass and one attachment
|
||||
TEST_F(RenderPassValidationTest, OneSubpassOneAttachment) {
|
||||
AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
// without a load op
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Tests for setting attachment load ops
|
||||
TEST_F(RenderPassValidationTest, AttachmentLoadOps) {
|
||||
AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
// with a load op
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
// with a load op of the wrong type - this is okay, just ignored
|
||||
.AttachmentSetDepthStencilLoadOps(0, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Test for attachment slot arguments out of bounds
|
||||
TEST_F(RenderPassValidationTest, AttachmentOutOfBounds) {
|
||||
// Control case
|
||||
AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
// Test AttachmentSetFormat slot out of bounds
|
||||
.AttachmentSetFormat(1, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
// Test AttachmentSetColorLoadOp slot out of bounds
|
||||
.AttachmentSetColorLoadOp(1, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
// Test AttachmentSetDepthStencilLoadOps slot out of bounds
|
||||
.AttachmentSetDepthStencilLoadOps(1, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
// Test SubpassSetColorAttachment attachment slot out of bounds
|
||||
.SubpassSetColorAttachment(0, 0, 1)
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
// Test SubpassSetDepthStencilAttachment attachment slot out of bounds
|
||||
.SubpassSetDepthStencilAttachment(0, 1)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Test for subpass arguments out of bounds
|
||||
TEST_F(RenderPassValidationTest, SubpassOutOfBounds) {
|
||||
// Control case
|
||||
AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
// Test SubpassSetColorAttachment subpass out of bounds
|
||||
.SubpassSetColorAttachment(1, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::D32FloatS8Uint)
|
||||
// Test SubpassSetDepthStencilAttachment subpass out of bounds
|
||||
.SubpassSetDepthStencilAttachment(1, 0)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Test attaching depth/stencil textures to color attachments and vice versa
|
||||
TEST_F(RenderPassValidationTest, SubpassAttachmentWrongAspect) {
|
||||
AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SubpassSetDepthStencilAttachment(0, 0)
|
||||
.GetResult();
|
||||
|
||||
AssertWillBeError(device.CreateRenderPassBuilder())
|
||||
.SetSubpassCount(1)
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::D32FloatS8Uint)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "tests/unittests/validation/ValidationTest.h"
|
||||
|
||||
#include "common/Constants.h"
|
||||
#include "utils/NXTHelpers.h"
|
||||
|
||||
class RenderPipelineValidationTest : public ValidationTest {
|
||||
|
@ -21,7 +22,7 @@ class RenderPipelineValidationTest : public ValidationTest {
|
|||
void SetUp() override {
|
||||
ValidationTest::SetUp();
|
||||
|
||||
CreateSimpleRenderPassAndFramebuffer(device, &renderpass, &framebuffer);
|
||||
renderpass = CreateSimpleRenderPass();
|
||||
|
||||
pipelineLayout = device.CreatePipelineLayoutBuilder().GetResult();
|
||||
|
||||
|
@ -45,7 +46,7 @@ class RenderPipelineValidationTest : public ValidationTest {
|
|||
}
|
||||
|
||||
nxt::RenderPipelineBuilder& AddDefaultStates(nxt::RenderPipelineBuilder&& builder) {
|
||||
builder.SetSubpass(renderpass, 0)
|
||||
builder.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -53,8 +54,7 @@ class RenderPipelineValidationTest : public ValidationTest {
|
|||
return builder;
|
||||
}
|
||||
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::RenderPassInfo renderpass;
|
||||
nxt::ShaderModule vsModule;
|
||||
nxt::ShaderModule fsModule;
|
||||
nxt::InputState inputState;
|
||||
|
@ -81,7 +81,7 @@ TEST_F(RenderPipelineValidationTest, CreationMissingProperty) {
|
|||
// Vertex stage not set
|
||||
{
|
||||
AssertWillBeError(device.CreateRenderPipelineBuilder())
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList)
|
||||
|
@ -91,14 +91,14 @@ TEST_F(RenderPipelineValidationTest, CreationMissingProperty) {
|
|||
// Fragment stage not set
|
||||
{
|
||||
AssertWillBeError(device.CreateRenderPipelineBuilder())
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Subpass not set
|
||||
// No attachment set
|
||||
{
|
||||
AssertWillBeError(device.CreateRenderPipelineBuilder())
|
||||
.SetLayout(pipelineLayout)
|
||||
|
@ -112,47 +112,9 @@ TEST_F(RenderPipelineValidationTest, CreationMissingProperty) {
|
|||
TEST_F(RenderPipelineValidationTest, BlendState) {
|
||||
// Fails because blend state is set on a nonexistent color attachment
|
||||
{
|
||||
auto texture1 = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(640, 480, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
texture1.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
auto textureView1 = texture1.CreateTextureViewBuilder()
|
||||
.GetResult();
|
||||
|
||||
auto texture2 = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(640, 480, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
texture2.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
auto textureView2 = texture2.CreateTextureViewBuilder()
|
||||
.GetResult();
|
||||
|
||||
auto renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(2)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetFormat(1, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
auto framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(640, 480)
|
||||
.SetAttachment(0, textureView1)
|
||||
.SetAttachment(1, textureView2)
|
||||
.GetResult();
|
||||
|
||||
|
||||
// This one succeeds because attachment 0 is the subpass's color attachment
|
||||
// This one succeeds because attachment 0 is the color attachment
|
||||
AssertWillBeSuccess(device.CreateRenderPipelineBuilder())
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -160,9 +122,9 @@ TEST_F(RenderPipelineValidationTest, BlendState) {
|
|||
.SetColorAttachmentBlendState(0, blendState)
|
||||
.GetResult();
|
||||
|
||||
// This fails because attachment 1 is not one of the subpass's color attachments
|
||||
// This fails because attachment 1 is not one of the color attachments
|
||||
AssertWillBeError(device.CreateRenderPipelineBuilder())
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -174,7 +136,7 @@ TEST_F(RenderPipelineValidationTest, BlendState) {
|
|||
// Fails because color attachment is out of bounds
|
||||
{
|
||||
AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder()))
|
||||
.SetColorAttachmentBlendState(1, blendState)
|
||||
.SetColorAttachmentBlendState(kMaxColorAttachments, blendState)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
|
@ -192,7 +154,7 @@ TEST_F(RenderPipelineValidationTest, DISABLED_TodoCreationMissingProperty) {
|
|||
// Fails because pipeline layout is not set
|
||||
{
|
||||
AssertWillBeError(device.CreateRenderPipelineBuilder())
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList)
|
||||
|
@ -202,7 +164,7 @@ TEST_F(RenderPipelineValidationTest, DISABLED_TodoCreationMissingProperty) {
|
|||
// Fails because primitive topology is not set
|
||||
{
|
||||
AssertWillBeError(device.CreateRenderPipelineBuilder())
|
||||
.SetSubpass(renderpass, 0)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetLayout(pipelineLayout)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
|
@ -240,13 +202,6 @@ TEST_F(RenderPipelineValidationTest, DISABLED_CreationDuplicates) {
|
|||
.GetResult();
|
||||
}
|
||||
|
||||
// Fails because subpass is set twice
|
||||
{
|
||||
AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder()))
|
||||
.SetSubpass(renderpass, 0)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
// Fails because the layout is set twice
|
||||
{
|
||||
AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder()))
|
||||
|
|
|
@ -69,7 +69,7 @@ bool ValidationTest::EndExpectDeviceError() {
|
|||
return mError;
|
||||
}
|
||||
|
||||
void ValidationTest::CreateSimpleRenderPassAndFramebuffer(const nxt::Device& device, nxt::RenderPass* renderpass, nxt::Framebuffer* framebuffer) {
|
||||
nxt::RenderPassInfo ValidationTest::CreateSimpleRenderPass() {
|
||||
auto colorBuffer = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(640, 480, 1)
|
||||
|
@ -81,17 +81,8 @@ void ValidationTest::CreateSimpleRenderPassAndFramebuffer(const nxt::Device& dev
|
|||
auto colorView = colorBuffer.CreateTextureViewBuilder()
|
||||
.GetResult();
|
||||
|
||||
*renderpass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
*framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(*renderpass)
|
||||
.SetDimensions(640, 480)
|
||||
.SetAttachment(0, colorView)
|
||||
return device.CreateRenderPassInfoBuilder()
|
||||
.SetColorAttachment(0, colorView, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
|
@ -128,13 +119,6 @@ ValidationTest::DummyRenderPass ValidationTest::CreateDummyRenderPass() {
|
|||
dummy.height = 400;
|
||||
dummy.attachmentFormat = nxt::TextureFormat::R8G8B8A8Unorm;
|
||||
|
||||
dummy.renderPass = AssertWillBeSuccess(device.CreateRenderPassBuilder())
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, dummy.attachmentFormat)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
dummy.attachment = AssertWillBeSuccess(device.CreateTextureBuilder())
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(dummy.width, dummy.height, 1)
|
||||
|
@ -146,10 +130,8 @@ ValidationTest::DummyRenderPass ValidationTest::CreateDummyRenderPass() {
|
|||
|
||||
nxt::TextureView view = AssertWillBeSuccess(dummy.attachment.CreateTextureViewBuilder()).GetResult();
|
||||
|
||||
dummy.framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
|
||||
.SetRenderPass(dummy.renderPass)
|
||||
.SetAttachment(0, view)
|
||||
.SetDimensions(dummy.width, dummy.height)
|
||||
dummy.renderPass = AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
|
||||
.SetColorAttachment(0, view, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
|
||||
return dummy;
|
||||
|
|
|
@ -48,13 +48,12 @@ class ValidationTest : public testing::Test {
|
|||
void StartExpectDeviceError();
|
||||
bool EndExpectDeviceError();
|
||||
|
||||
void CreateSimpleRenderPassAndFramebuffer(const nxt::Device& device, nxt::RenderPass* renderpass, nxt::Framebuffer* framebuffer);
|
||||
nxt::RenderPassInfo CreateSimpleRenderPass();
|
||||
|
||||
// Helper functions to create objects to test validation.
|
||||
|
||||
struct DummyRenderPass {
|
||||
nxt::RenderPass renderPass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::RenderPassInfo renderPass;
|
||||
nxt::Texture attachment;
|
||||
nxt::TextureFormat attachmentFormat;
|
||||
uint32_t width;
|
||||
|
|
|
@ -23,6 +23,8 @@ class VertexBufferValidationTest : public ValidationTest {
|
|||
void SetUp() override {
|
||||
ValidationTest::SetUp();
|
||||
|
||||
renderpass = CreateSimpleRenderPass();
|
||||
|
||||
fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
|
||||
#version 450
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
@ -31,36 +33,6 @@ class VertexBufferValidationTest : public ValidationTest {
|
|||
})");
|
||||
}
|
||||
|
||||
void MakeRenderPassAndFrameBuffer(uint32_t subpassCount) {
|
||||
auto colorBuffer = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(640, 480, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
|
||||
.GetResult();
|
||||
colorBuffer.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
|
||||
auto colorView = colorBuffer.CreateTextureViewBuilder()
|
||||
.GetResult();
|
||||
|
||||
auto renderpassBuilder = device.CreateRenderPassBuilder();
|
||||
renderpassBuilder.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetSubpassCount(subpassCount);
|
||||
|
||||
for (uint32_t i = 0; i < subpassCount; ++i) {
|
||||
renderpassBuilder.SubpassSetColorAttachment(i, 0, 0);
|
||||
}
|
||||
|
||||
renderpass = renderpassBuilder.GetResult();
|
||||
|
||||
framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(renderpass)
|
||||
.SetDimensions(640, 480)
|
||||
.SetAttachment(0, colorView)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
template <unsigned int N>
|
||||
std::array<nxt::Buffer, N> MakeVertexBuffers() {
|
||||
std::array<nxt::Buffer, N> buffers;
|
||||
|
@ -105,102 +77,89 @@ class VertexBufferValidationTest : public ValidationTest {
|
|||
return builder.GetResult();
|
||||
}
|
||||
|
||||
nxt::RenderPipeline MakeRenderPipeline(uint32_t subpass, const nxt::ShaderModule& vsModule, const nxt::InputState& inputState) {
|
||||
nxt::RenderPipeline MakeRenderPipeline(const nxt::ShaderModule& vsModule, const nxt::InputState& inputState) {
|
||||
return device.CreateRenderPipelineBuilder()
|
||||
.SetSubpass(renderpass, subpass)
|
||||
.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
|
||||
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
|
||||
.SetInputState(inputState)
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
nxt::RenderPass renderpass;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::RenderPassInfo renderpass;
|
||||
nxt::ShaderModule fsModule;
|
||||
};
|
||||
|
||||
TEST_F(VertexBufferValidationTest, VertexInputsInheritedBetweenPipelines) {
|
||||
MakeRenderPassAndFrameBuffer(1);
|
||||
|
||||
auto vsModule2 = MakeVertexShader(2);
|
||||
auto vsModule1 = MakeVertexShader(1);
|
||||
|
||||
auto inputState2 = MakeInputState(2);
|
||||
auto inputState1 = MakeInputState(1);
|
||||
|
||||
auto pipeline2 = MakeRenderPipeline(0, vsModule2, inputState2);
|
||||
auto pipeline1 = MakeRenderPipeline(0, vsModule1, inputState1);
|
||||
auto pipeline2 = MakeRenderPipeline(vsModule2, inputState2);
|
||||
auto pipeline1 = MakeRenderPipeline(vsModule1, inputState1);
|
||||
|
||||
auto vertexBuffers = MakeVertexBuffers<2>();
|
||||
uint32_t offsets[] = { 0, 0 };
|
||||
|
||||
// Check failure when vertex buffer is not set
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(pipeline1)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderPass(renderpass)
|
||||
.SetRenderPipeline(pipeline1)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
// Check success when vertex buffer is inherited from previous pipeline
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(pipeline2)
|
||||
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.SetRenderPipeline(pipeline1)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderPass(renderpass)
|
||||
.SetRenderPipeline(pipeline2)
|
||||
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.SetRenderPipeline(pipeline1)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
||||
TEST_F(VertexBufferValidationTest, VertexInputsNotInheritedBetweenSubpasses) {
|
||||
MakeRenderPassAndFrameBuffer(2);
|
||||
|
||||
TEST_F(VertexBufferValidationTest, VertexInputsNotInheritedBetweenRendePasses) {
|
||||
auto vsModule2 = MakeVertexShader(2);
|
||||
auto vsModule1 = MakeVertexShader(1);
|
||||
|
||||
auto inputState2 = MakeInputState(2);
|
||||
auto inputState1 = MakeInputState(1);
|
||||
|
||||
auto pipeline2 = MakeRenderPipeline(0, vsModule2, inputState2);
|
||||
auto pipeline1 = MakeRenderPipeline(1, vsModule1, inputState1);
|
||||
auto pipeline2 = MakeRenderPipeline(vsModule2, inputState2);
|
||||
auto pipeline1 = MakeRenderPipeline(vsModule1, inputState1);
|
||||
|
||||
auto vertexBuffers = MakeVertexBuffers<2>();
|
||||
uint32_t offsets[] = { 0, 0 };
|
||||
|
||||
// Check success when vertex buffer is set for each subpass
|
||||
// Check success when vertex buffer is set for each render pass
|
||||
AssertWillBeSuccess(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(pipeline2)
|
||||
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(pipeline1)
|
||||
.SetVertexBuffers(0, 1, vertexBuffers.data(), offsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderPass(renderpass)
|
||||
.SetRenderPipeline(pipeline2)
|
||||
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.BeginRenderPass(renderpass)
|
||||
.SetRenderPipeline(pipeline1)
|
||||
.SetVertexBuffers(0, 1, vertexBuffers.data(), offsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
|
||||
// Check failure because vertex buffer is not inherited in second subpass
|
||||
AssertWillBeError(device.CreateCommandBufferBuilder())
|
||||
.BeginRenderPass(renderpass, framebuffer)
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(pipeline2)
|
||||
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderSubpass()
|
||||
.SetRenderPipeline(pipeline1)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderSubpass()
|
||||
.BeginRenderPass(renderpass)
|
||||
.SetRenderPipeline(pipeline2)
|
||||
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.BeginRenderPass(renderpass)
|
||||
.SetRenderPipeline(pipeline1)
|
||||
.DrawArrays(3, 1, 0, 0)
|
||||
.EndRenderPass()
|
||||
.GetResult();
|
||||
}
|
||||
|
|
|
@ -111,25 +111,18 @@ namespace utils {
|
|||
return buffer;
|
||||
}
|
||||
|
||||
BasicFramebuffer CreateBasicFramebuffer(const nxt::Device& device,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
BasicFramebuffer result;
|
||||
BasicRenderPass CreateBasicRenderPass(const nxt::Device& device,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
BasicRenderPass result;
|
||||
result.width = width;
|
||||
result.height = height;
|
||||
|
||||
result.renderPass = device.CreateRenderPassBuilder()
|
||||
.SetAttachmentCount(1)
|
||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||
.SetSubpassCount(1)
|
||||
.SubpassSetColorAttachment(0, 0, 0)
|
||||
.GetResult();
|
||||
|
||||
result.colorFormat = nxt::TextureFormat::R8G8B8A8Unorm;
|
||||
result.color = device.CreateTextureBuilder()
|
||||
.SetDimension(nxt::TextureDimension::e2D)
|
||||
.SetExtent(width, height, 1)
|
||||
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm)
|
||||
.SetFormat(result.colorFormat)
|
||||
.SetMipLevels(1)
|
||||
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment |
|
||||
nxt::TextureUsageBit::TransferSrc)
|
||||
|
@ -137,12 +130,9 @@ namespace utils {
|
|||
.GetResult();
|
||||
|
||||
nxt::TextureView colorView = result.color.CreateTextureViewBuilder().GetResult();
|
||||
|
||||
result.framebuffer = device.CreateFramebufferBuilder()
|
||||
.SetRenderPass(result.renderPass)
|
||||
.SetAttachment(0, colorView)
|
||||
.SetDimensions(width, height)
|
||||
.GetResult();
|
||||
result.renderPassInfo = device.CreateRenderPassInfoBuilder()
|
||||
.SetColorAttachment(0, colorView, nxt::LoadOp::Clear)
|
||||
.GetResult();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -37,15 +37,15 @@ namespace utils {
|
|||
usage);
|
||||
}
|
||||
|
||||
struct BasicFramebuffer {
|
||||
struct BasicRenderPass {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
nxt::RenderPass renderPass;
|
||||
nxt::Texture color;
|
||||
nxt::Framebuffer framebuffer;
|
||||
nxt::TextureFormat colorFormat;
|
||||
nxt::RenderPassInfo renderPassInfo;
|
||||
};
|
||||
BasicFramebuffer CreateBasicFramebuffer(const nxt::Device& device,
|
||||
uint32_t width,
|
||||
uint32_t height);
|
||||
BasicRenderPass CreateBasicRenderPass(const nxt::Device& device,
|
||||
uint32_t width,
|
||||
uint32_t height);
|
||||
|
||||
} // namespace utils
|
||||
|
|
Loading…
Reference in New Issue