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:
Corentin Wallez 2018-05-02 18:10:13 -04:00 committed by Corentin Wallez
parent 87ec361cc2
commit 6f7749cce9
92 changed files with 1869 additions and 3168 deletions

View File

@ -26,7 +26,6 @@ nxt::Queue queue;
nxt::SwapChain swapchain; nxt::SwapChain swapchain;
nxt::TextureView depthStencilView; nxt::TextureView depthStencilView;
nxt::RenderPipeline pipeline; nxt::RenderPipeline pipeline;
nxt::RenderPass renderpass;
float RandomFloat(float min, float max) { float RandomFloat(float min, float max) {
float zeroOne = rand() / float(RAND_MAX); float zeroOne = rand() / float(RAND_MAX);
@ -108,11 +107,11 @@ void init() {
fragColor = v_color; fragColor = v_color;
})"); })");
renderpass = CreateDefaultRenderPass(device);
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
pipeline = device.CreateRenderPipelineBuilder() pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.GetResult(); .GetResult();
@ -130,8 +129,8 @@ void init() {
void frame() { void frame() {
nxt::Texture backbuffer; nxt::Texture backbuffer;
nxt::Framebuffer framebuffer; nxt::RenderPassInfo renderPass;
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer); GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
static int f = 0; static int f = 0;
f++; f++;
@ -141,8 +140,7 @@ void frame() {
nxt::CommandBuffer commands; nxt::CommandBuffer commands;
{ {
nxt::CommandBufferBuilder builder = device.CreateCommandBufferBuilder() nxt::CommandBufferBuilder builder = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.Clone(); .Clone();
@ -153,7 +151,6 @@ void frame() {
i++; i++;
} }
builder.EndRenderSubpass();
builder.EndRenderPass(); builder.EndRenderPass();
commands = builder.GetResult(); commands = builder.GetResult();
} }

View File

@ -21,7 +21,6 @@ nxtDevice device;
nxtQueue queue; nxtQueue queue;
nxtSwapChain swapchain; nxtSwapChain swapchain;
nxtRenderPipeline pipeline; nxtRenderPipeline pipeline;
nxtRenderPass renderpass;
nxtTextureFormat swapChainFormat; nxtTextureFormat swapChainFormat;
@ -61,18 +60,9 @@ void init() {
"}\n"; "}\n";
nxtShaderModule fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, fs).Release(); 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); 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_VERTEX, vsModule, "main");
nxtRenderPipelineBuilderSetStage(builder, NXT_SHADER_STAGE_FRAGMENT, fsModule, "main"); nxtRenderPipelineBuilderSetStage(builder, NXT_SHADER_STAGE_FRAGMENT, fsModule, "main");
pipeline = nxtRenderPipelineBuilderGetResult(builder); pipeline = nxtRenderPipelineBuilderGetResult(builder);
@ -91,23 +81,19 @@ void frame() {
backbufferView = nxtTextureViewBuilderGetResult(builder); backbufferView = nxtTextureViewBuilderGetResult(builder);
nxtTextureViewBuilderRelease(builder); nxtTextureViewBuilderRelease(builder);
} }
nxtFramebuffer framebuffer; nxtRenderPassInfo renderpassInfo;
{ {
nxtFramebufferBuilder builder = nxtDeviceCreateFramebufferBuilder(device); nxtRenderPassInfoBuilder builder = nxtDeviceCreateRenderPassInfoBuilder(device);
nxtFramebufferBuilderSetRenderPass(builder, renderpass); nxtRenderPassInfoBuilderSetColorAttachment(builder, 0, backbufferView, NXT_LOAD_OP_CLEAR);
nxtFramebufferBuilderSetDimensions(builder, 640, 480); renderpassInfo = nxtRenderPassInfoBuilderGetResult(builder);
nxtFramebufferBuilderSetAttachment(builder, 0, backbufferView); nxtRenderPassInfoBuilderRelease(builder);
framebuffer = nxtFramebufferBuilderGetResult(builder);
nxtFramebufferBuilderRelease(builder);
} }
nxtCommandBuffer commands; nxtCommandBuffer commands;
{ {
nxtCommandBufferBuilder builder = nxtDeviceCreateCommandBufferBuilder(device); nxtCommandBufferBuilder builder = nxtDeviceCreateCommandBufferBuilder(device);
nxtCommandBufferBuilderBeginRenderPass(builder, renderpass, framebuffer); nxtCommandBufferBuilderBeginRenderPass(builder, renderpassInfo);
nxtCommandBufferBuilderBeginRenderSubpass(builder);
nxtCommandBufferBuilderSetRenderPipeline(builder, pipeline); nxtCommandBufferBuilderSetRenderPipeline(builder, pipeline);
nxtCommandBufferBuilderDrawArrays(builder, 3, 1, 0, 0); nxtCommandBufferBuilderDrawArrays(builder, 3, 1, 0, 0);
nxtCommandBufferBuilderEndRenderSubpass(builder);
nxtCommandBufferBuilderEndRenderPass(builder); nxtCommandBufferBuilderEndRenderPass(builder);
commands = nxtCommandBufferBuilderGetResult(builder); commands = nxtCommandBufferBuilderGetResult(builder);
nxtCommandBufferBuilderRelease(builder); nxtCommandBufferBuilderRelease(builder);
@ -117,7 +103,7 @@ void frame() {
nxtCommandBufferRelease(commands); nxtCommandBufferRelease(commands);
nxtTextureTransitionUsage(backbuffer, NXT_TEXTURE_USAGE_BIT_PRESENT); nxtTextureTransitionUsage(backbuffer, NXT_TEXTURE_USAGE_BIT_PRESENT);
nxtSwapChainPresent(swapchain, backbuffer); nxtSwapChainPresent(swapchain, backbuffer);
nxtFramebufferRelease(framebuffer); nxtRenderPassInfoRelease(renderpassInfo);
nxtTextureViewRelease(backbufferView); nxtTextureViewRelease(backbufferView);
DoFlush(); DoFlush();

View File

@ -32,7 +32,6 @@ nxt::Buffer modelBuffer;
std::array<nxt::Buffer, 2> particleBuffers; std::array<nxt::Buffer, 2> particleBuffers;
nxt::RenderPipeline renderPipeline; nxt::RenderPipeline renderPipeline;
nxt::RenderPass renderpass;
nxt::Buffer updateParams; nxt::Buffer updateParams;
nxt::ComputePipeline updatePipeline; nxt::ComputePipeline updatePipeline;
@ -123,11 +122,11 @@ void initRender() {
.SetInput(1, sizeof(glm::vec2), nxt::InputStepMode::Vertex) .SetInput(1, sizeof(glm::vec2), nxt::InputStepMode::Vertex)
.GetResult(); .GetResult();
renderpass = CreateDefaultRenderPass(device);
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
renderPipeline = device.CreateRenderPipelineBuilder() renderPipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetInputState(inputState) .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}; static const uint32_t zeroOffsets[1] = {0};
auto& bufferSrc = particleBuffers[i]; auto& bufferSrc = particleBuffers[i];
auto& bufferDst = particleBuffers[(i + 1) % 2]; auto& bufferDst = particleBuffers[(i + 1) % 2];
@ -273,14 +272,12 @@ nxt::CommandBuffer createCommandBuffer(const nxt::Framebuffer& framebuffer, size
.Dispatch(kNumParticles, 1, 1) .Dispatch(kNumParticles, 1, 1)
.EndComputePass() .EndComputePass()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass)
.BeginRenderSubpass()
.SetRenderPipeline(renderPipeline) .SetRenderPipeline(renderPipeline)
.TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Vertex) .TransitionBufferUsage(bufferDst, nxt::BufferUsageBit::Vertex)
.SetVertexBuffers(0, 1, &bufferDst, zeroOffsets) .SetVertexBuffers(0, 1, &bufferDst, zeroOffsets)
.SetVertexBuffers(1, 1, &modelBuffer, zeroOffsets) .SetVertexBuffers(1, 1, &modelBuffer, zeroOffsets)
.DrawArrays(3, kNumParticles, 0, 0) .DrawArrays(3, kNumParticles, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
@ -301,10 +298,10 @@ void init() {
void frame() { void frame() {
nxt::Texture backbuffer; nxt::Texture backbuffer;
nxt::Framebuffer framebuffer; nxt::RenderPassInfo renderPass;
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer); GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
nxt::CommandBuffer commandBuffer = createCommandBuffer(framebuffer, pingpong); nxt::CommandBuffer commandBuffer = createCommandBuffer(renderPass, pingpong);
queue.Submit(1, &commandBuffer); queue.Submit(1, &commandBuffer);
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present); backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
swapchain.Present(backbuffer); swapchain.Present(backbuffer);

View File

@ -26,7 +26,6 @@ nxt::TextureView depthStencilView;
nxt::Buffer buffer; nxt::Buffer buffer;
nxt::RenderPipeline renderPipeline; nxt::RenderPipeline renderPipeline;
nxt::BindGroup renderBindGroup; nxt::BindGroup renderBindGroup;
nxt::RenderPass renderpass;
nxt::ComputePipeline computePipeline; nxt::ComputePipeline computePipeline;
nxt::BindGroup computeBindGroup; nxt::BindGroup computeBindGroup;
@ -113,11 +112,11 @@ void init() {
.SetBindGroupLayout(0, bgl) .SetBindGroupLayout(0, bgl)
.GetResult(); .GetResult();
renderpass = CreateDefaultRenderPass(device);
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
renderPipeline = device.CreateRenderPipelineBuilder() renderPipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetLayout(pl) .SetLayout(pl)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -133,8 +132,8 @@ void init() {
void frame() { void frame() {
nxt::Texture backbuffer; nxt::Texture backbuffer;
nxt::Framebuffer framebuffer; nxt::RenderPassInfo renderPass;
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer); GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.TransitionBufferUsage(buffer, nxt::BufferUsageBit::Storage) .TransitionBufferUsage(buffer, nxt::BufferUsageBit::Storage)
@ -145,12 +144,10 @@ void frame() {
.EndComputePass() .EndComputePass()
.TransitionBufferUsage(buffer, nxt::BufferUsageBit::Uniform) .TransitionBufferUsage(buffer, nxt::BufferUsageBit::Uniform)
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass)
.BeginRenderSubpass()
.SetRenderPipeline(renderPipeline) .SetRenderPipeline(renderPipeline)
.SetBindGroup(0, renderBindGroup) .SetBindGroup(0, renderBindGroup)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();

View File

@ -40,7 +40,6 @@ nxt::TextureView depthStencilView;
nxt::RenderPipeline pipeline; nxt::RenderPipeline pipeline;
nxt::RenderPipeline planePipeline; nxt::RenderPipeline planePipeline;
nxt::RenderPipeline reflectionPipeline; nxt::RenderPipeline reflectionPipeline;
nxt::RenderPass renderpass;
void initBuffers() { void initBuffers() {
static const uint32_t indexData[6*6] = { static const uint32_t indexData[6*6] = {
@ -209,7 +208,6 @@ void init() {
.SetBufferViews(1, 1, &transformBufferView[1]) .SetBufferViews(1, 1, &transformBufferView[1])
.GetResult(); .GetResult();
renderpass = CreateDefaultRenderPass(device);
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
auto depthStencilState = device.CreateDepthStencilStateBuilder() auto depthStencilState = device.CreateDepthStencilStateBuilder()
@ -218,7 +216,8 @@ void init() {
.GetResult(); .GetResult();
pipeline = device.CreateRenderPipelineBuilder() pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetLayout(pl) .SetLayout(pl)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -234,7 +233,8 @@ void init() {
.GetResult(); .GetResult();
planePipeline = device.CreateRenderPipelineBuilder() planePipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetLayout(pl) .SetLayout(pl)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -249,7 +249,8 @@ void init() {
.GetResult(); .GetResult();
reflectionPipeline = device.CreateRenderPipelineBuilder() reflectionPipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetLayout(pl) .SetLayout(pl)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsReflectionModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsReflectionModule, "main")
@ -277,12 +278,11 @@ void frame() {
cameraBuffer.SetSubData(0, sizeof(CameraData), reinterpret_cast<uint8_t*>(&cameraData)); cameraBuffer.SetSubData(0, sizeof(CameraData), reinterpret_cast<uint8_t*>(&cameraData));
nxt::Texture backbuffer; nxt::Texture backbuffer;
nxt::Framebuffer framebuffer; nxt::RenderPassInfo renderPass;
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer); GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.TransitionBufferUsage(cameraBuffer, nxt::BufferUsageBit::Uniform) .TransitionBufferUsage(cameraBuffer, nxt::BufferUsageBit::Uniform)
.SetBindGroup(0, bindGroup[0]) .SetBindGroup(0, bindGroup[0])
@ -300,7 +300,6 @@ void frame() {
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets) .SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
.SetBindGroup(0, bindGroup[1]) .SetBindGroup(0, bindGroup[1])
.DrawElements(36, 1, 0, 0) .DrawElements(36, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();

View File

@ -28,7 +28,6 @@ nxt::Queue queue;
nxt::SwapChain swapchain; nxt::SwapChain swapchain;
nxt::TextureView depthStencilView; nxt::TextureView depthStencilView;
nxt::RenderPipeline pipeline; nxt::RenderPipeline pipeline;
nxt::RenderPass renderpass;
void initBuffers() { void initBuffers() {
static const uint32_t indexData[3] = { static const uint32_t indexData[3] = {
@ -74,11 +73,11 @@ void init() {
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex) .SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
.GetResult(); .GetResult();
renderpass = CreateDefaultRenderPass(device);
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
pipeline = device.CreateRenderPipelineBuilder() pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetIndexFormat(nxt::IndexFormat::Uint32) .SetIndexFormat(nxt::IndexFormat::Uint32)
@ -88,18 +87,16 @@ void init() {
void frame() { void frame() {
nxt::Texture backbuffer; nxt::Texture backbuffer;
nxt::Framebuffer framebuffer; nxt::RenderPassInfo renderPass;
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer); GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
static const uint32_t vertexBufferOffsets[1] = {0}; static const uint32_t vertexBufferOffsets[1] = {0};
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets) .SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
.SetIndexBuffer(indexBuffer, 0) .SetIndexBuffer(indexBuffer, 0)
.DrawElements(3, 1, 0, 0) .DrawElements(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();

View File

@ -28,7 +28,6 @@ nxt::Queue queue;
nxt::SwapChain swapchain; nxt::SwapChain swapchain;
nxt::TextureView depthStencilView; nxt::TextureView depthStencilView;
nxt::RenderPipeline pipeline; nxt::RenderPipeline pipeline;
nxt::RenderPass renderpass;
void initBuffers() { void initBuffers() {
static const float vertexData[12] = { static const float vertexData[12] = {
@ -80,11 +79,11 @@ void init() {
.SetInput(1, 2 * sizeof(float), nxt::InputStepMode::Instance) .SetInput(1, 2 * sizeof(float), nxt::InputStepMode::Instance)
.GetResult(); .GetResult();
renderpass = CreateDefaultRenderPass(device);
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
pipeline = device.CreateRenderPipelineBuilder() pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetInputState(inputState) .SetInputState(inputState)
@ -93,18 +92,16 @@ void init() {
void frame() { void frame() {
nxt::Texture backbuffer; nxt::Texture backbuffer;
nxt::Framebuffer framebuffer; nxt::RenderPassInfo renderPass;
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer); GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
static const uint32_t vertexBufferOffsets[1] = {0}; static const uint32_t vertexBufferOffsets[1] = {0};
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets) .SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
.SetVertexBuffers(1, 1, &instanceBuffer, vertexBufferOffsets) .SetVertexBuffers(1, 1, &instanceBuffer, vertexBufferOffsets)
.DrawArrays(3, 4, 0, 0) .DrawArrays(3, 4, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();

View File

@ -31,7 +31,6 @@ nxt::Queue queue;
nxt::SwapChain swapchain; nxt::SwapChain swapchain;
nxt::TextureView depthStencilView; nxt::TextureView depthStencilView;
nxt::RenderPipeline pipeline; nxt::RenderPipeline pipeline;
nxt::RenderPass renderpass;
nxt::BindGroup bindGroup; nxt::BindGroup bindGroup;
void initBuffers() { void initBuffers() {
@ -121,11 +120,11 @@ void init() {
.SetBindGroupLayout(0, bgl) .SetBindGroupLayout(0, bgl)
.GetResult(); .GetResult();
renderpass = CreateDefaultRenderPass(device);
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
pipeline = device.CreateRenderPipelineBuilder() pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetLayout(pl) .SetLayout(pl)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -150,19 +149,17 @@ void frame() {
if (s.b >= 1.0f) {s.b = 0.0f;} if (s.b >= 1.0f) {s.b = 0.0f;}
nxt::Texture backbuffer; nxt::Texture backbuffer;
nxt::Framebuffer framebuffer; nxt::RenderPassInfo renderPass;
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer); GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
static const uint32_t vertexBufferOffsets[1] = {0}; static const uint32_t vertexBufferOffsets[1] = {0};
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetBindGroup(0, bindGroup) .SetBindGroup(0, bindGroup)
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets) .SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
.SetIndexBuffer(indexBuffer, 0) .SetIndexBuffer(indexBuffer, 0)
.DrawElements(3, 1, 0, 0) .DrawElements(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();

View File

@ -22,7 +22,6 @@ nxt::Queue queue;
nxt::SwapChain swapchain; nxt::SwapChain swapchain;
nxt::TextureView depthStencilView; nxt::TextureView depthStencilView;
nxt::RenderPipeline pipeline; nxt::RenderPipeline pipeline;
nxt::RenderPass renderpass;
nxt::Buffer buffer; nxt::Buffer buffer;
nxt::BindGroup bindGroup; nxt::BindGroup bindGroup;
@ -63,11 +62,11 @@ void init() {
.SetBindGroupLayout(0, bgl) .SetBindGroupLayout(0, bgl)
.GetResult(); .GetResult();
renderpass = CreateDefaultRenderPass(device);
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
pipeline = device.CreateRenderPipelineBuilder() pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetLayout(pl) .SetLayout(pl)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -99,17 +98,15 @@ void frame() {
buffer.SetSubData(0, sizeof(s), reinterpret_cast<uint8_t*>(&s)); buffer.SetSubData(0, sizeof(s), reinterpret_cast<uint8_t*>(&s));
nxt::Texture backbuffer; nxt::Texture backbuffer;
nxt::Framebuffer framebuffer; nxt::RenderPassInfo renderPass;
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer); GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.TransitionBufferUsage(buffer, nxt::BufferUsageBit::Uniform) .TransitionBufferUsage(buffer, nxt::BufferUsageBit::Uniform)
.SetBindGroup(0, bindGroup) .SetBindGroup(0, bindGroup)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();

View File

@ -27,7 +27,6 @@ nxt::Queue queue;
nxt::SwapChain swapchain; nxt::SwapChain swapchain;
nxt::TextureView depthStencilView; nxt::TextureView depthStencilView;
nxt::RenderPipeline pipeline; nxt::RenderPipeline pipeline;
nxt::RenderPass renderpass;
void initBuffers() { void initBuffers() {
static const float vertexData[12] = { static const float vertexData[12] = {
@ -69,11 +68,11 @@ void init() {
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex) .SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
.GetResult(); .GetResult();
renderpass = CreateDefaultRenderPass(device);
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
pipeline = device.CreateRenderPipelineBuilder() pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetInputState(inputState) .SetInputState(inputState)
@ -82,17 +81,15 @@ void init() {
void frame() { void frame() {
nxt::Texture backbuffer; nxt::Texture backbuffer;
nxt::Framebuffer framebuffer; nxt::RenderPassInfo renderPass;
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer); GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
static const uint32_t vertexBufferOffsets[1] = {0}; static const uint32_t vertexBufferOffsets[1] = {0};
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets) .SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();

View File

@ -33,7 +33,6 @@ nxt::SwapChain swapchain;
nxt::RenderPipeline pipeline; nxt::RenderPipeline pipeline;
nxt::RenderPipeline pipelinePost; nxt::RenderPipeline pipelinePost;
nxt::BindGroup bindGroup; nxt::BindGroup bindGroup;
nxt::RenderPass renderpass;
void initBuffers() { void initBuffers() {
static const float vertexData[12] = { static const float vertexData[12] = {
@ -70,19 +69,6 @@ void initTextures() {
.GetResult(); .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() { void initPipeline() {
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"( nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
#version 450 #version 450
@ -106,7 +92,7 @@ void initPipeline() {
.GetResult(); .GetResult();
pipeline = device.CreateRenderPipelineBuilder() pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetInputState(inputState) .SetInputState(inputState)
@ -147,7 +133,7 @@ void initPipelinePost() {
.GetResult(); .GetResult();
pipelinePost = device.CreateRenderPipelineBuilder() pipelinePost = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 1) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pl) .SetLayout(pl)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -172,7 +158,6 @@ void init() {
initBuffers(); initBuffers();
initTextures(); initTextures();
initRenderPass();
initPipeline(); initPipeline();
initPipelinePost(); initPipelinePost();
} }
@ -180,30 +165,30 @@ void init() {
void frame() { void frame() {
nxt::Texture backbuffer = swapchain.GetNextTexture(); nxt::Texture backbuffer = swapchain.GetNextTexture();
auto backbufferView = backbuffer.CreateTextureViewBuilder().GetResult(); auto backbufferView = backbuffer.CreateTextureViewBuilder().GetResult();
auto framebuffer = device.CreateFramebufferBuilder()
.SetRenderPass(renderpass) nxt::RenderPassInfo renderPass1 = device.CreateRenderPassInfoBuilder()
.SetDimensions(640, 480) .SetColorAttachment(0, renderTargetView, nxt::LoadOp::Clear)
.SetAttachment(0, renderTargetView) .GetResult();
.SetAttachment(1, backbufferView)
nxt::RenderPassInfo renderPass2 = device.CreateRenderPassInfoBuilder()
.SetColorAttachment(0, backbufferView, nxt::LoadOp::Clear)
.GetResult(); .GetResult();
static const uint32_t vertexBufferOffsets[1] = {0}; static const uint32_t vertexBufferOffsets[1] = {0};
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass1)
.BeginRenderSubpass()
// renderTarget implicitly locked to to Attachment usage (if not already frozen) // renderTarget implicitly locked to to Attachment usage (if not already frozen)
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets) .SetVertexBuffers(0, 1, &vertexBuffer, vertexBufferOffsets)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass() .EndRenderPass()
// renderTarget usage unlocked, but left in Attachment usage // renderTarget usage unlocked, but left in Attachment usage
.BeginRenderSubpass() .TransitionTextureUsage(renderTarget, nxt::TextureUsageBit::Sampled)
.BeginRenderPass(renderPass2)
.SetRenderPipeline(pipelinePost) .SetRenderPipeline(pipelinePost)
.SetVertexBuffers(0, 1, &vertexBufferQuad, vertexBufferOffsets) .SetVertexBuffers(0, 1, &vertexBufferQuad, vertexBufferOffsets)
.TransitionTextureUsage(renderTarget, nxt::TextureUsageBit::Sampled)
.SetBindGroup(0, bindGroup) .SetBindGroup(0, bindGroup)
.DrawArrays(6, 1, 0, 0) .DrawArrays(6, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();

View File

@ -134,19 +134,6 @@ nxt::SwapChain GetSwapChain(const nxt::Device &device) {
.GetResult(); .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) { nxt::TextureView CreateDefaultDepthStencilView(const nxt::Device& device) {
auto depthStencilTexture = device.CreateTextureBuilder() auto depthStencilTexture = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D) .SetDimension(nxt::TextureDimension::e2D)
@ -160,19 +147,16 @@ nxt::TextureView CreateDefaultDepthStencilView(const nxt::Device& device) {
.GetResult(); .GetResult();
} }
void GetNextFramebuffer(const nxt::Device& device, void GetNextRenderPassInfo(const nxt::Device& device,
const nxt::RenderPass& renderpass,
const nxt::SwapChain& swapchain, const nxt::SwapChain& swapchain,
const nxt::TextureView& depthStencilView, const nxt::TextureView& depthStencilView,
nxt::Texture* backbuffer, nxt::Texture* backbuffer,
nxt::Framebuffer* framebuffer) { nxt::RenderPassInfo* info) {
*backbuffer = swapchain.GetNextTexture(); *backbuffer = swapchain.GetNextTexture();
auto backbufferView = backbuffer->CreateTextureViewBuilder().GetResult(); auto backbufferView = backbuffer->CreateTextureViewBuilder().GetResult();
*framebuffer = device.CreateFramebufferBuilder() *info = device.CreateRenderPassInfoBuilder()
.SetRenderPass(renderpass) .SetColorAttachment(0, backbufferView, nxt::LoadOp::Clear)
.SetDimensions(640, 480) .SetDepthStencilAttachment(depthStencilView, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
.SetAttachment(0, backbufferView)
.SetAttachment(1, depthStencilView)
.GetResult(); .GetResult();
} }

View File

@ -26,11 +26,9 @@ nxt::Device CreateCppNXTDevice();
uint64_t GetSwapChainImplementation(); uint64_t GetSwapChainImplementation();
nxt::TextureFormat GetPreferredSwapChainTextureFormat(); nxt::TextureFormat GetPreferredSwapChainTextureFormat();
nxt::SwapChain GetSwapChain(const nxt::Device& device); nxt::SwapChain GetSwapChain(const nxt::Device& device);
nxt::RenderPass CreateDefaultRenderPass(const nxt::Device& device);
nxt::TextureView CreateDefaultDepthStencilView(const nxt::Device& device); nxt::TextureView CreateDefaultDepthStencilView(const nxt::Device& device);
void GetNextFramebuffer(const nxt::Device& device, void GetNextRenderPassInfo(const nxt::Device& device,
const nxt::RenderPass& renderPass,
const nxt::SwapChain& swapchain, const nxt::SwapChain& swapchain,
const nxt::TextureView& depthStencilView, const nxt::TextureView& depthStencilView,
nxt::Texture* backbuffer, nxt::Texture* backbuffer,
nxt::Framebuffer* framebuffer); nxt::RenderPassInfo* info);

View File

@ -79,7 +79,6 @@ nxt::Device device;
nxt::Queue queue; nxt::Queue queue;
nxt::SwapChain swapchain; nxt::SwapChain swapchain;
nxt::TextureView depthStencilView; nxt::TextureView depthStencilView;
nxt::RenderPass renderpass;
nxt::Buffer defaultBuffer; nxt::Buffer defaultBuffer;
std::map<std::string, nxt::Buffer> buffers; std::map<std::string, nxt::Buffer> buffers;
@ -291,7 +290,8 @@ namespace {
.SetBindGroupLayout(0, bindGroupLayout) .SetBindGroupLayout(0, bindGroupLayout)
.GetResult(); .GetResult();
auto pipeline = device.CreateRenderPipelineBuilder() auto pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, GetPreferredSwapChainTextureFormat())
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, oVSModule, "main") .SetStage(nxt::ShaderStage::Vertex, oVSModule, "main")
.SetStage(nxt::ShaderStage::Fragment, oFSModule, "main") .SetStage(nxt::ShaderStage::Fragment, oFSModule, "main")
@ -468,7 +468,6 @@ namespace {
swapchain.Configure(GetPreferredSwapChainTextureFormat(), swapchain.Configure(GetPreferredSwapChainTextureFormat(),
nxt::TextureUsageBit::OutputAttachment, 640, 480); nxt::TextureUsageBit::OutputAttachment, 640, 480);
renderpass = CreateDefaultRenderPass(device);
depthStencilView = CreateDefaultDepthStencilView(device); depthStencilView = CreateDefaultDepthStencilView(device);
initBuffers(); initBuffers();
@ -585,21 +584,18 @@ namespace {
void frame() { void frame() {
nxt::Texture backbuffer; nxt::Texture backbuffer;
nxt::Framebuffer framebuffer; nxt::RenderPassInfo renderPass;
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer); GetNextRenderPassInfo(device, swapchain, depthStencilView, &backbuffer, &renderPass);
framebuffer.AttachmentSetClearColor(0, 0.3f, 0.4f, 0.5f, 1);
const auto& defaultSceneNodes = scene.scenes.at(scene.defaultScene); const auto& defaultSceneNodes = scene.scenes.at(scene.defaultScene);
nxt::CommandBufferBuilder cmd = device.CreateCommandBufferBuilder() nxt::CommandBufferBuilder cmd = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass)
.BeginRenderSubpass()
.Clone(); .Clone();
for (const auto& n : defaultSceneNodes) { for (const auto& n : defaultSceneNodes) {
const auto& node = scene.nodes.at(n); const auto& node = scene.nodes.at(n);
drawNode(cmd, node); drawNode(cmd, node);
} }
auto commands = cmd.EndRenderSubpass() auto commands = cmd.EndRenderPass()
.EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); queue.Submit(1, &commands);

152
next.json
View File

@ -345,13 +345,9 @@
{ {
"name": "begin render pass", "name": "begin render pass",
"args": [ "args": [
{"name": "render pass", "type": "render pass"}, {"name": "info", "type": "render pass info"}
{"name": "framebuffer", "type": "framebuffer"}
] ]
}, },
{
"name": "begin render subpass"
},
{ {
"name": "copy buffer to buffer", "name": "copy buffer to buffer",
"args": [ "args": [
@ -441,9 +437,6 @@
{ {
"name": "end render pass" "name": "end render pass"
}, },
{
"name": "end render subpass"
},
{ {
"name": "set stencil reference", "name": "set stencil reference",
"args": [ "args": [
@ -599,8 +592,8 @@
"returns": "depth stencil state builder" "returns": "depth stencil state builder"
}, },
{ {
"name": "create framebuffer builder", "name": "create render pass info builder",
"returns": "framebuffer builder" "returns": "render pass info builder"
}, },
{ {
"name": "create input state builder", "name": "create input state builder",
@ -622,10 +615,6 @@
"name": "create queue builder", "name": "create queue builder",
"returns": "queue builder" "returns": "queue builder"
}, },
{
"name": "create render pass builder",
"returns": "render pass builder"
},
{ {
"name": "create sampler builder", "name": "create sampler builder",
"returns": "sampler builder" "returns": "sampler builder"
@ -725,60 +714,6 @@
"float": { "float": {
"category": "native" "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": { "index format": {
"category": "enum", "category": "enum",
"values": [ "values": [
@ -879,70 +814,51 @@
} }
] ]
}, },
"render pass builder": { "render pass info builder": {
"category": "object", "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": [ "methods": [
{ {
"name": "get result", "name": "get result",
"returns": "render pass" "returns": "render pass info"
}, },
{ {
"name": "set attachment count", "name": "set color attachment",
"args": [
{"name": "attachment count", "type": "uint32_t"}
]
},
{
"name": "attachment set format",
"TODO": "Also need sample count",
"args": [ "args": [
{"name": "attachment slot", "type": "uint32_t"}, {"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": [ "args": [
{"name": "attachment slot", "type": "uint32_t"}, {"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": [ "args": [
{"name": "attachment slot", "type": "uint32_t"}, {"name": "texture view", "type": "texture view"},
{"name": "depth op", "type": "load op"}, {"name": "depth load op", "type": "load op"},
{"name": "stencil 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": [ "args": [
{"name": "subpass count", "type": "uint32_t"} {"name": "clear depth", "type": "float"},
] {"name": "clear stencil", "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"}
] ]
} }
] ]
}, },
"render pass": { "render pass info": {
"category": "object" "category": "object"
}, },
"render pipeline": { "render pipeline": {
@ -955,6 +871,21 @@
"name": "get result", "name": "get result",
"returns": "render pipeline" "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", "name": "set color attachment blend state",
"args": [ "args": [
@ -999,13 +930,6 @@
{"name": "module", "type": "shader module"}, {"name": "module", "type": "shader module"},
{"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"} {"name": "entry point", "type": "char", "annotation": "const*", "length": "strlen"}
] ]
},
{
"name": "set subpass",
"args": [
{"name": "render pass", "type": "render pass"},
{"name": "subpass", "type": "uint32_t"}
]
} }
] ]
}, },

View File

@ -40,7 +40,8 @@ namespace backend {
} }
for (uint32_t binding : IterateBitSet(a.mask)) { 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; return false;
} }
} }

View File

@ -241,8 +241,6 @@ if (NXT_ENABLE_D3D12)
${D3D12_DIR}/DescriptorHeapAllocator.h ${D3D12_DIR}/DescriptorHeapAllocator.h
${D3D12_DIR}/D3D12Backend.cpp ${D3D12_DIR}/D3D12Backend.cpp
${D3D12_DIR}/D3D12Backend.h ${D3D12_DIR}/D3D12Backend.h
${D3D12_DIR}/FramebufferD3D12.cpp
${D3D12_DIR}/FramebufferD3D12.h
${D3D12_DIR}/InputStateD3D12.cpp ${D3D12_DIR}/InputStateD3D12.cpp
${D3D12_DIR}/InputStateD3D12.h ${D3D12_DIR}/InputStateD3D12.h
${D3D12_DIR}/NativeSwapChainImplD3D12.cpp ${D3D12_DIR}/NativeSwapChainImplD3D12.cpp
@ -251,6 +249,8 @@ if (NXT_ENABLE_D3D12)
${D3D12_DIR}/PipelineLayoutD3D12.h ${D3D12_DIR}/PipelineLayoutD3D12.h
${D3D12_DIR}/QueueD3D12.cpp ${D3D12_DIR}/QueueD3D12.cpp
${D3D12_DIR}/QueueD3D12.h ${D3D12_DIR}/QueueD3D12.h
${D3D12_DIR}/RenderPassInfoD3D12.cpp
${D3D12_DIR}/RenderPassInfoD3D12.h
${D3D12_DIR}/RenderPipelineD3D12.cpp ${D3D12_DIR}/RenderPipelineD3D12.cpp
${D3D12_DIR}/RenderPipelineD3D12.h ${D3D12_DIR}/RenderPipelineD3D12.h
${D3D12_DIR}/ResourceAllocator.cpp ${D3D12_DIR}/ResourceAllocator.cpp
@ -308,8 +308,6 @@ if (NXT_ENABLE_VULKAN)
${VULKAN_DIR}/DepthStencilStateVk.h ${VULKAN_DIR}/DepthStencilStateVk.h
${VULKAN_DIR}/FencedDeleter.cpp ${VULKAN_DIR}/FencedDeleter.cpp
${VULKAN_DIR}/FencedDeleter.h ${VULKAN_DIR}/FencedDeleter.h
${VULKAN_DIR}/FramebufferVk.cpp
${VULKAN_DIR}/FramebufferVk.h
${VULKAN_DIR}/InputStateVk.cpp ${VULKAN_DIR}/InputStateVk.cpp
${VULKAN_DIR}/InputStateVk.h ${VULKAN_DIR}/InputStateVk.h
${VULKAN_DIR}/MemoryAllocator.cpp ${VULKAN_DIR}/MemoryAllocator.cpp
@ -318,8 +316,10 @@ if (NXT_ENABLE_VULKAN)
${VULKAN_DIR}/NativeSwapChainImplVk.h ${VULKAN_DIR}/NativeSwapChainImplVk.h
${VULKAN_DIR}/PipelineLayoutVk.cpp ${VULKAN_DIR}/PipelineLayoutVk.cpp
${VULKAN_DIR}/PipelineLayoutVk.h ${VULKAN_DIR}/PipelineLayoutVk.h
${VULKAN_DIR}/RenderPassVk.cpp ${VULKAN_DIR}/RenderPassCache.cpp
${VULKAN_DIR}/RenderPassVk.h ${VULKAN_DIR}/RenderPassCache.h
${VULKAN_DIR}/RenderPassInfoVk.cpp
${VULKAN_DIR}/RenderPassInfoVk.h
${VULKAN_DIR}/RenderPipelineVk.cpp ${VULKAN_DIR}/RenderPipelineVk.cpp
${VULKAN_DIR}/RenderPipelineVk.h ${VULKAN_DIR}/RenderPipelineVk.h
${VULKAN_DIR}/SamplerVk.cpp ${VULKAN_DIR}/SamplerVk.cpp
@ -367,8 +367,6 @@ list(APPEND BACKEND_SOURCES
${BACKEND_DIR}/Device.cpp ${BACKEND_DIR}/Device.cpp
${BACKEND_DIR}/Device.h ${BACKEND_DIR}/Device.h
${BACKEND_DIR}/Forward.h ${BACKEND_DIR}/Forward.h
${BACKEND_DIR}/Framebuffer.cpp
${BACKEND_DIR}/Framebuffer.h
${BACKEND_DIR}/InputState.cpp ${BACKEND_DIR}/InputState.cpp
${BACKEND_DIR}/InputState.h ${BACKEND_DIR}/InputState.h
${BACKEND_DIR}/RenderPipeline.cpp ${BACKEND_DIR}/RenderPipeline.cpp
@ -381,8 +379,8 @@ list(APPEND BACKEND_SOURCES
${BACKEND_DIR}/PipelineLayout.h ${BACKEND_DIR}/PipelineLayout.h
${BACKEND_DIR}/Queue.cpp ${BACKEND_DIR}/Queue.cpp
${BACKEND_DIR}/Queue.h ${BACKEND_DIR}/Queue.h
${BACKEND_DIR}/RenderPass.cpp ${BACKEND_DIR}/RenderPassInfo.cpp
${BACKEND_DIR}/RenderPass.h ${BACKEND_DIR}/RenderPassInfo.h
${BACKEND_DIR}/RefCounted.cpp ${BACKEND_DIR}/RefCounted.cpp
${BACKEND_DIR}/RefCounted.h ${BACKEND_DIR}/RefCounted.h
${BACKEND_DIR}/Sampler.cpp ${BACKEND_DIR}/Sampler.cpp

View File

@ -162,10 +162,6 @@ namespace backend {
BeginRenderPassCmd* begin = commands->NextCommand<BeginRenderPassCmd>(); BeginRenderPassCmd* begin = commands->NextCommand<BeginRenderPassCmd>();
begin->~BeginRenderPassCmd(); begin->~BeginRenderPassCmd();
} break; } break;
case Command::BeginRenderSubpass: {
BeginRenderSubpassCmd* begin = commands->NextCommand<BeginRenderSubpassCmd>();
begin->~BeginRenderSubpassCmd();
} break;
case Command::CopyBufferToBuffer: { case Command::CopyBufferToBuffer: {
CopyBufferToBufferCmd* copy = commands->NextCommand<CopyBufferToBufferCmd>(); CopyBufferToBufferCmd* copy = commands->NextCommand<CopyBufferToBufferCmd>();
copy->~CopyBufferToBufferCmd(); copy->~CopyBufferToBufferCmd();
@ -198,10 +194,6 @@ namespace backend {
EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>(); EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>();
cmd->~EndRenderPassCmd(); cmd->~EndRenderPassCmd();
} break; } break;
case Command::EndRenderSubpass: {
EndRenderSubpassCmd* cmd = commands->NextCommand<EndRenderSubpassCmd>();
cmd->~EndRenderSubpassCmd();
} break;
case Command::SetComputePipeline: { case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>(); SetComputePipelineCmd* cmd = commands->NextCommand<SetComputePipelineCmd>();
cmd->~SetComputePipelineCmd(); cmd->~SetComputePipelineCmd();
@ -269,10 +261,6 @@ namespace backend {
commands->NextCommand<BeginRenderPassCmd>(); commands->NextCommand<BeginRenderPassCmd>();
break; break;
case Command::BeginRenderSubpass:
commands->NextCommand<BeginRenderSubpassCmd>();
break;
case Command::CopyBufferToBuffer: case Command::CopyBufferToBuffer:
commands->NextCommand<CopyBufferToBufferCmd>(); commands->NextCommand<CopyBufferToBufferCmd>();
break; break;
@ -305,10 +293,6 @@ namespace backend {
commands->NextCommand<EndRenderPassCmd>(); commands->NextCommand<EndRenderPassCmd>();
break; break;
case Command::EndRenderSubpass:
commands->NextCommand<EndRenderSubpassCmd>();
break;
case Command::SetComputePipeline: case Command::SetComputePipeline:
commands->NextCommand<SetComputePipelineCmd>(); commands->NextCommand<SetComputePipelineCmd>();
break; break;
@ -384,25 +368,8 @@ namespace backend {
case Command::BeginRenderPass: { case Command::BeginRenderPass: {
BeginRenderPassCmd* cmd = mIterator.NextCommand<BeginRenderPassCmd>(); BeginRenderPassCmd* cmd = mIterator.NextCommand<BeginRenderPassCmd>();
auto* renderPass = cmd->renderPass.Get(); RenderPassInfoBase* info = cmd->info.Get();
auto* framebuffer = cmd->framebuffer.Get(); if (!mState->BeginRenderPass(info)) {
// 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()) {
return false; return false;
} }
} break; } break;
@ -495,13 +462,6 @@ namespace backend {
} }
} break; } break;
case Command::EndRenderSubpass: {
mIterator.NextCommand<EndRenderSubpassCmd>();
if (!mState->EndSubpass()) {
return false;
}
} break;
case Command::SetComputePipeline: { case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = mIterator.NextCommand<SetComputePipelineCmd>(); SetComputePipelineCmd* cmd = mIterator.NextCommand<SetComputePipelineCmd>();
ComputePipelineBase* pipeline = cmd->pipeline.Get(); ComputePipelineBase* pipeline = cmd->pipeline.Get();
@ -531,24 +491,24 @@ namespace backend {
case Command::SetStencilReference: { case Command::SetStencilReference: {
mIterator.NextCommand<SetStencilReferenceCmd>(); mIterator.NextCommand<SetStencilReferenceCmd>();
if (!mState->HaveRenderSubpass()) { if (!mState->HaveRenderPass()) {
HandleError("Can't set stencil reference without an active render subpass"); HandleError("Can't set stencil reference without an active render pass");
return false; return false;
} }
} break; } break;
case Command::SetBlendColor: { case Command::SetBlendColor: {
mIterator.NextCommand<SetBlendColorCmd>(); mIterator.NextCommand<SetBlendColorCmd>();
if (!mState->HaveRenderSubpass()) { if (!mState->HaveRenderPass()) {
HandleError("Can't set blend color without an active render subpass"); HandleError("Can't set blend color without an active render pass");
return false; return false;
} }
} break; } break;
case Command::SetScissorRect: { case Command::SetScissorRect: {
mIterator.NextCommand<SetScissorRectCmd>(); mIterator.NextCommand<SetScissorRectCmd>();
if (!mState->HaveRenderSubpass()) { if (!mState->HaveRenderPass()) {
HandleError("Can't set scissor rect without an active render subpass"); HandleError("Can't set scissor rect without an active render pass");
return false; return false;
} }
} break; } break;
@ -618,16 +578,10 @@ namespace backend {
mAllocator.Allocate<BeginComputePassCmd>(Command::BeginComputePass); mAllocator.Allocate<BeginComputePassCmd>(Command::BeginComputePass);
} }
void CommandBufferBuilder::BeginRenderPass(RenderPassBase* renderPass, void CommandBufferBuilder::BeginRenderPass(RenderPassInfoBase* info) {
FramebufferBase* framebuffer) {
BeginRenderPassCmd* cmd = mAllocator.Allocate<BeginRenderPassCmd>(Command::BeginRenderPass); BeginRenderPassCmd* cmd = mAllocator.Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
new (cmd) BeginRenderPassCmd; new (cmd) BeginRenderPassCmd;
cmd->renderPass = renderPass; cmd->info = info;
cmd->framebuffer = framebuffer;
}
void CommandBufferBuilder::BeginRenderSubpass() {
mAllocator.Allocate<BeginRenderSubpassCmd>(Command::BeginRenderSubpass);
} }
void CommandBufferBuilder::CopyBufferToBuffer(BufferBase* source, void CommandBufferBuilder::CopyBufferToBuffer(BufferBase* source,
@ -745,10 +699,6 @@ namespace backend {
mAllocator.Allocate<EndRenderPassCmd>(Command::EndRenderPass); mAllocator.Allocate<EndRenderPassCmd>(Command::EndRenderPass);
} }
void CommandBufferBuilder::EndRenderSubpass() {
mAllocator.Allocate<EndRenderSubpassCmd>(Command::EndRenderSubpass);
}
void CommandBufferBuilder::SetComputePipeline(ComputePipelineBase* pipeline) { void CommandBufferBuilder::SetComputePipeline(ComputePipelineBase* pipeline) {
SetComputePipelineCmd* cmd = SetComputePipelineCmd* cmd =
mAllocator.Allocate<SetComputePipelineCmd>(Command::SetComputePipeline); mAllocator.Allocate<SetComputePipelineCmd>(Command::SetComputePipeline);

View File

@ -62,8 +62,7 @@ namespace backend {
// NXT API // NXT API
void BeginComputePass(); void BeginComputePass();
void BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer); void BeginRenderPass(RenderPassInfoBase* info);
void BeginRenderSubpass();
void CopyBufferToBuffer(BufferBase* source, void CopyBufferToBuffer(BufferBase* source,
uint32_t sourceOffset, uint32_t sourceOffset,
BufferBase* destination, BufferBase* destination,
@ -102,7 +101,6 @@ namespace backend {
uint32_t firstInstance); uint32_t firstInstance);
void EndComputePass(); void EndComputePass();
void EndRenderPass(); void EndRenderPass();
void EndRenderSubpass();
void SetPushConstants(nxt::ShaderStageBit stages, void SetPushConstants(nxt::ShaderStageBit stages,
uint32_t offset, uint32_t offset,
uint32_t count, uint32_t count,

View File

@ -19,10 +19,9 @@
#include "backend/Buffer.h" #include "backend/Buffer.h"
#include "backend/ComputePipeline.h" #include "backend/ComputePipeline.h"
#include "backend/Forward.h" #include "backend/Forward.h"
#include "backend/Framebuffer.h"
#include "backend/InputState.h" #include "backend/InputState.h"
#include "backend/PipelineLayout.h" #include "backend/PipelineLayout.h"
#include "backend/RenderPass.h" #include "backend/RenderPassInfo.h"
#include "backend/RenderPipeline.h" #include "backend/RenderPipeline.h"
#include "backend/Texture.h" #include "backend/Texture.h"
#include "common/Assert.h" #include "common/Assert.h"
@ -37,10 +36,6 @@ namespace backend {
return mCurrentRenderPass != nullptr; return mCurrentRenderPass != nullptr;
} }
bool CommandBufferStateTracker::HaveRenderSubpass() const {
return mAspects[VALIDATION_ASPECT_RENDER_SUBPASS];
}
bool CommandBufferStateTracker::ValidateCanCopy() const { bool CommandBufferStateTracker::ValidateCanCopy() const {
if (mCurrentRenderPass) { if (mCurrentRenderPass) {
mBuilder->HandleError("Copy cannot occur during a render pass"); mBuilder->HandleError("Copy cannot occur during a render pass");
@ -91,7 +86,7 @@ namespace backend {
bool CommandBufferStateTracker::ValidateCanDrawArrays() { bool CommandBufferStateTracker::ValidateCanDrawArrays() {
// TODO(kainino@chromium.org): Check for a current render pass // TODO(kainino@chromium.org): Check for a current render pass
constexpr ValidationAspects requiredAspects = 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; 1 << VALIDATION_ASPECT_BIND_GROUPS | 1 << VALIDATION_ASPECT_VERTEX_BUFFERS;
if ((requiredAspects & ~mAspects).none()) { if ((requiredAspects & ~mAspects).none()) {
// Fast return-true path if everything is good // Fast return-true path if everything is good
@ -137,15 +132,16 @@ namespace backend {
"SetPushConstants stage must be compute or 0 in compute passes"); "SetPushConstants stage must be compute or 0 in compute passes");
return false; return false;
} }
} else if (mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) { } else if (mAspects[VALIDATION_ASPECT_RENDER_PASS]) {
if (stages & ~(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) { if (stages & ~(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
mBuilder->HandleError( 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; return false;
} }
} else { } else {
mBuilder->HandleError( 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 false;
} }
return true; return true;
@ -170,64 +166,7 @@ namespace backend {
return true; return true;
} }
bool CommandBufferStateTracker::BeginSubpass() { bool CommandBufferStateTracker::BeginRenderPass(RenderPassInfoBase* info) {
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) {
if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) { if (mAspects[VALIDATION_ASPECT_COMPUTE_PASS]) {
mBuilder->HandleError("Cannot begin a render pass while a compute pass is active"); mBuilder->HandleError("Cannot begin a render pass while a compute pass is active");
return false; return false;
@ -236,15 +175,27 @@ namespace backend {
mBuilder->HandleError("A render pass is already active"); mBuilder->HandleError("A render pass is already active");
return false; return false;
} }
ASSERT(!mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]);
if (!framebuffer->GetRenderPass()->IsCompatibleWith(renderPass)) { mCurrentRenderPass = info;
mBuilder->HandleError("Framebuffer is incompatible with this render pass"); 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; return false;
} }
mTexturesAttached.insert(texture);
}
mCurrentRenderPass = renderPass; if (info->HasDepthStencilAttachment()) {
mCurrentFramebuffer = framebuffer; TextureBase* texture = info->GetDepthStencilAttachment().view->GetTexture();
mCurrentSubpass = 0; if (!EnsureTextureUsage(texture, nxt::TextureUsageBit::OutputAttachment)) {
mBuilder->HandleError("Unable to ensure texture has OutputAttachment usage");
return false;
}
mTexturesAttached.insert(texture);
}
return true; return true;
} }
@ -254,16 +205,15 @@ namespace backend {
mBuilder->HandleError("No render pass is currently active"); mBuilder->HandleError("No render pass is currently active");
return false; return false;
} }
if (mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) {
mBuilder->HandleError("Can't end a render pass while a subpass is active"); // Everything in mTexturesAttached should be for the current render pass.
return false; mTexturesAttached.clear();
}
if (mCurrentSubpass < mCurrentRenderPass->GetSubpassCount() - 1) { mInputsSet.reset();
mBuilder->HandleError("Can't end a render pass before the last subpass"); UnsetPipeline();
return false;
} mAspects.reset(VALIDATION_ASPECT_RENDER_PASS);
mCurrentRenderPass = nullptr; mCurrentRenderPass = nullptr;
mCurrentFramebuffer = nullptr;
return true; return true;
} }
@ -284,11 +234,11 @@ namespace backend {
} }
bool CommandBufferStateTracker::SetRenderPipeline(RenderPipelineBase* pipeline) { bool CommandBufferStateTracker::SetRenderPipeline(RenderPipelineBase* pipeline) {
if (!mAspects[VALIDATION_ASPECT_RENDER_SUBPASS]) { if (!mAspects[VALIDATION_ASPECT_RENDER_PASS]) {
mBuilder->HandleError("A render subpass must be active when a render pipeline is set"); mBuilder->HandleError("A render pass must be active when a render pipeline is set");
return false; return false;
} }
if (!pipeline->GetRenderPass()->IsCompatibleWith(mCurrentRenderPass)) { if (!pipeline->IsCompatibleWith(mCurrentRenderPass)) {
mBuilder->HandleError("Pipeline is incompatible with this render pass"); mBuilder->HandleError("Pipeline is incompatible with this render pass");
return false; return false;
} }

View File

@ -30,7 +30,6 @@ namespace backend {
// Non-state-modifying validation functions // Non-state-modifying validation functions
bool HaveRenderPass() const; bool HaveRenderPass() const;
bool HaveRenderSubpass() const;
bool ValidateCanCopy() const; bool ValidateCanCopy() const;
bool ValidateCanUseBufferAs(BufferBase* buffer, nxt::BufferUsageBit usage) const; bool ValidateCanUseBufferAs(BufferBase* buffer, nxt::BufferUsageBit usage) const;
bool ValidateCanUseTextureAs(TextureBase* texture, nxt::TextureUsageBit usage) const; bool ValidateCanUseTextureAs(TextureBase* texture, nxt::TextureUsageBit usage) const;
@ -43,9 +42,7 @@ namespace backend {
// State-modifying methods // State-modifying methods
bool BeginComputePass(); bool BeginComputePass();
bool EndComputePass(); bool EndComputePass();
bool BeginSubpass(); bool BeginRenderPass(RenderPassInfoBase* info);
bool EndSubpass();
bool BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer);
bool EndRenderPass(); bool EndRenderPass();
bool SetComputePipeline(ComputePipelineBase* pipeline); bool SetComputePipeline(ComputePipelineBase* pipeline);
bool SetRenderPipeline(RenderPipelineBase* pipeline); bool SetRenderPipeline(RenderPipelineBase* pipeline);
@ -70,7 +67,7 @@ namespace backend {
VALIDATION_ASPECT_BIND_GROUPS, VALIDATION_ASPECT_BIND_GROUPS,
VALIDATION_ASPECT_VERTEX_BUFFERS, VALIDATION_ASPECT_VERTEX_BUFFERS,
VALIDATION_ASPECT_INDEX_BUFFER, VALIDATION_ASPECT_INDEX_BUFFER,
VALIDATION_ASPECT_RENDER_SUBPASS, VALIDATION_ASPECT_RENDER_PASS,
VALIDATION_ASPECT_COMPUTE_PASS, VALIDATION_ASPECT_COMPUTE_PASS,
VALIDATION_ASPECT_COUNT VALIDATION_ASPECT_COUNT
@ -109,9 +106,7 @@ namespace backend {
std::map<BufferBase*, nxt::BufferUsageBit> mMostRecentBufferUsages; std::map<BufferBase*, nxt::BufferUsageBit> mMostRecentBufferUsages;
std::map<TextureBase*, nxt::TextureUsageBit> mMostRecentTextureUsages; std::map<TextureBase*, nxt::TextureUsageBit> mMostRecentTextureUsages;
RenderPassBase* mCurrentRenderPass = nullptr; RenderPassInfoBase* mCurrentRenderPass = nullptr;
FramebufferBase* mCurrentFramebuffer = nullptr;
uint32_t mCurrentSubpass = 0;
}; };
} // namespace backend } // namespace backend

View File

@ -15,8 +15,7 @@
#ifndef BACKEND_COMMANDS_H_ #ifndef BACKEND_COMMANDS_H_
#define BACKEND_COMMANDS_H_ #define BACKEND_COMMANDS_H_
#include "backend/Framebuffer.h" #include "backend/RenderPassInfo.h"
#include "backend/RenderPass.h"
#include "backend/Texture.h" #include "backend/Texture.h"
#include "nxt/nxtcpp.h" #include "nxt/nxtcpp.h"
@ -30,7 +29,6 @@ namespace backend {
enum class Command { enum class Command {
BeginComputePass, BeginComputePass,
BeginRenderPass, BeginRenderPass,
BeginRenderSubpass,
CopyBufferToBuffer, CopyBufferToBuffer,
CopyBufferToTexture, CopyBufferToTexture,
CopyTextureToBuffer, CopyTextureToBuffer,
@ -39,7 +37,6 @@ namespace backend {
DrawElements, DrawElements,
EndComputePass, EndComputePass,
EndRenderPass, EndRenderPass,
EndRenderSubpass,
SetComputePipeline, SetComputePipeline,
SetRenderPipeline, SetRenderPipeline,
SetPushConstants, SetPushConstants,
@ -56,12 +53,9 @@ namespace backend {
struct BeginComputePassCmd {}; struct BeginComputePassCmd {};
struct BeginRenderPassCmd { struct BeginRenderPassCmd {
Ref<RenderPassBase> renderPass; Ref<RenderPassInfoBase> info;
Ref<FramebufferBase> framebuffer;
}; };
struct BeginRenderSubpassCmd {};
struct BufferCopyLocation { struct BufferCopyLocation {
Ref<BufferBase> buffer; Ref<BufferBase> buffer;
uint32_t offset; uint32_t offset;
@ -116,8 +110,6 @@ namespace backend {
struct EndRenderPassCmd {}; struct EndRenderPassCmd {};
struct EndRenderSubpassCmd {};
struct SetComputePipelineCmd { struct SetComputePipelineCmd {
Ref<ComputePipelineBase> pipeline; Ref<ComputePipelineBase> pipeline;
}; };

View File

@ -21,11 +21,10 @@
#include "backend/CommandBuffer.h" #include "backend/CommandBuffer.h"
#include "backend/ComputePipeline.h" #include "backend/ComputePipeline.h"
#include "backend/DepthStencilState.h" #include "backend/DepthStencilState.h"
#include "backend/Framebuffer.h"
#include "backend/InputState.h" #include "backend/InputState.h"
#include "backend/PipelineLayout.h" #include "backend/PipelineLayout.h"
#include "backend/Queue.h" #include "backend/Queue.h"
#include "backend/RenderPass.h" #include "backend/RenderPassInfo.h"
#include "backend/RenderPipeline.h" #include "backend/RenderPipeline.h"
#include "backend/Sampler.h" #include "backend/Sampler.h"
#include "backend/ShaderModule.h" #include "backend/ShaderModule.h"
@ -116,9 +115,6 @@ namespace backend {
DepthStencilStateBuilder* DeviceBase::CreateDepthStencilStateBuilder() { DepthStencilStateBuilder* DeviceBase::CreateDepthStencilStateBuilder() {
return new DepthStencilStateBuilder(this); return new DepthStencilStateBuilder(this);
} }
FramebufferBuilder* DeviceBase::CreateFramebufferBuilder() {
return new FramebufferBuilder(this);
}
InputStateBuilder* DeviceBase::CreateInputStateBuilder() { InputStateBuilder* DeviceBase::CreateInputStateBuilder() {
return new InputStateBuilder(this); return new InputStateBuilder(this);
} }
@ -128,8 +124,8 @@ namespace backend {
QueueBuilder* DeviceBase::CreateQueueBuilder() { QueueBuilder* DeviceBase::CreateQueueBuilder() {
return new QueueBuilder(this); return new QueueBuilder(this);
} }
RenderPassBuilder* DeviceBase::CreateRenderPassBuilder() { RenderPassInfoBuilder* DeviceBase::CreateRenderPassInfoBuilder() {
return new RenderPassBuilder(this); return new RenderPassInfoBuilder(this);
} }
RenderPipelineBuilder* DeviceBase::CreateRenderPipelineBuilder() { RenderPipelineBuilder* DeviceBase::CreateRenderPipelineBuilder() {
return new RenderPipelineBuilder(this); return new RenderPipelineBuilder(this);

View File

@ -43,11 +43,10 @@ namespace backend {
virtual ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) = 0; virtual ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) = 0;
virtual DepthStencilStateBase* CreateDepthStencilState( virtual DepthStencilStateBase* CreateDepthStencilState(
DepthStencilStateBuilder* builder) = 0; DepthStencilStateBuilder* builder) = 0;
virtual FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) = 0;
virtual InputStateBase* CreateInputState(InputStateBuilder* builder) = 0; virtual InputStateBase* CreateInputState(InputStateBuilder* builder) = 0;
virtual PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) = 0; virtual PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) = 0;
virtual QueueBase* CreateQueue(QueueBuilder* 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 RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) = 0;
virtual SamplerBase* CreateSampler(SamplerBuilder* builder) = 0; virtual SamplerBase* CreateSampler(SamplerBuilder* builder) = 0;
virtual ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) = 0; virtual ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) = 0;
@ -83,11 +82,10 @@ namespace backend {
CommandBufferBuilder* CreateCommandBufferBuilder(); CommandBufferBuilder* CreateCommandBufferBuilder();
ComputePipelineBuilder* CreateComputePipelineBuilder(); ComputePipelineBuilder* CreateComputePipelineBuilder();
DepthStencilStateBuilder* CreateDepthStencilStateBuilder(); DepthStencilStateBuilder* CreateDepthStencilStateBuilder();
FramebufferBuilder* CreateFramebufferBuilder();
InputStateBuilder* CreateInputStateBuilder(); InputStateBuilder* CreateInputStateBuilder();
PipelineLayoutBuilder* CreatePipelineLayoutBuilder(); PipelineLayoutBuilder* CreatePipelineLayoutBuilder();
QueueBuilder* CreateQueueBuilder(); QueueBuilder* CreateQueueBuilder();
RenderPassBuilder* CreateRenderPassBuilder(); RenderPassInfoBuilder* CreateRenderPassInfoBuilder();
RenderPipelineBuilder* CreateRenderPipelineBuilder(); RenderPipelineBuilder* CreateRenderPipelineBuilder();
SamplerBuilder* CreateSamplerBuilder(); SamplerBuilder* CreateSamplerBuilder();
ShaderModuleBuilder* CreateShaderModuleBuilder(); ShaderModuleBuilder* CreateShaderModuleBuilder();

View File

@ -35,16 +35,14 @@ namespace backend {
class CommandBufferBuilder; class CommandBufferBuilder;
class DepthStencilStateBase; class DepthStencilStateBase;
class DepthStencilStateBuilder; class DepthStencilStateBuilder;
class FramebufferBase;
class FramebufferBuilder;
class InputStateBase; class InputStateBase;
class InputStateBuilder; class InputStateBuilder;
class PipelineLayoutBase; class PipelineLayoutBase;
class PipelineLayoutBuilder; class PipelineLayoutBuilder;
class QueueBase; class QueueBase;
class QueueBuilder; class QueueBuilder;
class RenderPassBase; class RenderPassInfoBase;
class RenderPassBuilder; class RenderPassInfoBuilder;
class RenderPipelineBase; class RenderPipelineBase;
class RenderPipelineBuilder; class RenderPipelineBuilder;
class SamplerBase; class SamplerBase;

View File

@ -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

View File

@ -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_

View File

@ -18,7 +18,6 @@
#include "backend/Device.h" #include "backend/Device.h"
#include "backend/InputState.h" #include "backend/InputState.h"
#include "backend/PipelineLayout.h" #include "backend/PipelineLayout.h"
#include "backend/RenderPass.h"
#include "backend/ShaderModule.h" #include "backend/ShaderModule.h"
namespace backend { namespace backend {

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -18,7 +18,8 @@
#include "backend/DepthStencilState.h" #include "backend/DepthStencilState.h"
#include "backend/Device.h" #include "backend/Device.h"
#include "backend/InputState.h" #include "backend/InputState.h"
#include "backend/RenderPass.h" #include "backend/RenderPassInfo.h"
#include "backend/Texture.h"
#include "common/BitSetIterator.h" #include "common/BitSetIterator.h"
namespace backend { namespace backend {
@ -32,8 +33,10 @@ namespace backend {
mInputState(std::move(builder->mInputState)), mInputState(std::move(builder->mInputState)),
mPrimitiveTopology(builder->mPrimitiveTopology), mPrimitiveTopology(builder->mPrimitiveTopology),
mBlendStates(builder->mBlendStates), mBlendStates(builder->mBlendStates),
mRenderPass(std::move(builder->mRenderPass)), mColorAttachmentsSet(builder->mColorAttachmentsSet),
mSubpass(builder->mSubpass) { mColorAttachmentFormats(builder->mColorAttachmentFormats),
mDepthStencilFormatSet(builder->mDepthStencilFormatSet),
mDepthStencilFormat(builder->mDepthStencilFormat) {
if (GetStageMask() != (nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) { if (GetStageMask() != (nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment)) {
builder->HandleError("Render pipeline should have exactly a vertex and fragment stage"); builder->HandleError("Render pipeline should have exactly a vertex and fragment stage");
return; return;
@ -47,6 +50,19 @@ namespace backend {
builder->HandleError("Pipeline vertex stage uses inputs not in the input state"); builder->HandleError("Pipeline vertex stage uses inputs not in the input state");
return; 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) { BlendStateBase* RenderPipelineBase::GetBlendState(uint32_t attachmentSlot) {
@ -70,12 +86,49 @@ namespace backend {
return mPrimitiveTopology; return mPrimitiveTopology;
} }
RenderPassBase* RenderPipelineBase::GetRenderPass() { std::bitset<kMaxColorAttachments> RenderPipelineBase::GetColorAttachmentsMask() const {
return mRenderPass.Get(); return mColorAttachmentsSet;
} }
uint32_t RenderPipelineBase::GetSubPass() { bool RenderPipelineBase::HasDepthStencilAttachment() const {
return mSubpass; 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 // RenderPipelineBuilder
@ -101,21 +154,15 @@ namespace backend {
mDepthStencilState->Release(); mDepthStencilState->Release();
builder->Release(); builder->Release();
} }
if (!mRenderPass) {
HandleError("Pipeline render pass not set"); if ((mBlendStatesSet | mColorAttachmentsSet) != mColorAttachmentsSet) {
return nullptr;
}
const auto& subpassInfo = mRenderPass->GetSubpassInfo(mSubpass);
if ((mBlendStatesSet | subpassInfo.colorAttachmentsSet) !=
subpassInfo.colorAttachmentsSet) {
HandleError("Blend state set on unset color attachment"); HandleError("Blend state set on unset color attachment");
return nullptr; return nullptr;
} }
// Assign all color attachments without a blend state the default state // Assign all color attachments without a blend state the default state
// TODO(enga@google.com): Put the default objects in the device // TODO(enga@google.com): Put the default objects in the device
for (uint32_t attachmentSlot : for (uint32_t attachmentSlot : IterateBitSet(mColorAttachmentsSet & ~mBlendStatesSet)) {
IterateBitSet(subpassInfo.colorAttachmentsSet & ~mBlendStatesSet)) {
mBlendStates[attachmentSlot] = mDevice->CreateBlendStateBuilder()->GetResult(); mBlendStates[attachmentSlot] = mDevice->CreateBlendStateBuilder()->GetResult();
// Remove the external ref objects are created with // Remove the external ref objects are created with
mBlendStates[attachmentSlot]->Release(); mBlendStates[attachmentSlot]->Release();
@ -124,9 +171,20 @@ namespace backend {
return mDevice->CreateRenderPipeline(this); 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, void RenderPipelineBuilder::SetColorAttachmentBlendState(uint32_t attachmentSlot,
BlendStateBase* blendState) { BlendStateBase* blendState) {
if (attachmentSlot > mBlendStates.size()) { if (attachmentSlot >= kMaxColorAttachments) {
HandleError("Attachment index out of bounds"); HandleError("Attachment index out of bounds");
return; return;
} }
@ -143,6 +201,11 @@ namespace backend {
mDepthStencilState = depthStencilState; mDepthStencilState = depthStencilState;
} }
void RenderPipelineBuilder::SetDepthStencilAttachmentFormat(nxt::TextureFormat format) {
mDepthStencilFormatSet = true;
mDepthStencilFormat = format;
}
void RenderPipelineBuilder::SetIndexFormat(nxt::IndexFormat format) { void RenderPipelineBuilder::SetIndexFormat(nxt::IndexFormat format) {
mIndexFormat = format; mIndexFormat = format;
} }
@ -155,9 +218,4 @@ namespace backend {
mPrimitiveTopology = primitiveTopology; mPrimitiveTopology = primitiveTopology;
} }
void RenderPipelineBuilder::SetSubpass(RenderPassBase* renderPass, uint32_t subpass) {
mRenderPass = renderPass;
mSubpass = subpass;
}
} // namespace backend } // namespace backend

View File

@ -19,7 +19,6 @@
#include "backend/DepthStencilState.h" #include "backend/DepthStencilState.h"
#include "backend/InputState.h" #include "backend/InputState.h"
#include "backend/Pipeline.h" #include "backend/Pipeline.h"
#include "backend/RenderPass.h"
#include "nxt/nxtcpp.h" #include "nxt/nxtcpp.h"
@ -37,8 +36,15 @@ namespace backend {
nxt::IndexFormat GetIndexFormat() const; nxt::IndexFormat GetIndexFormat() const;
InputStateBase* GetInputState(); InputStateBase* GetInputState();
nxt::PrimitiveTopology GetPrimitiveTopology() const; 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: private:
Ref<DepthStencilStateBase> mDepthStencilState; Ref<DepthStencilStateBase> mDepthStencilState;
@ -46,8 +52,11 @@ namespace backend {
Ref<InputStateBase> mInputState; Ref<InputStateBase> mInputState;
nxt::PrimitiveTopology mPrimitiveTopology; nxt::PrimitiveTopology mPrimitiveTopology;
std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates; 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 { class RenderPipelineBuilder : public Builder<RenderPipelineBase>, public PipelineBuilder {
@ -55,12 +64,13 @@ namespace backend {
RenderPipelineBuilder(DeviceBase* device); RenderPipelineBuilder(DeviceBase* device);
// NXT API // NXT API
void SetColorAttachmentFormat(uint32_t attachmentSlot, nxt::TextureFormat format);
void SetColorAttachmentBlendState(uint32_t attachmentSlot, BlendStateBase* blendState); void SetColorAttachmentBlendState(uint32_t attachmentSlot, BlendStateBase* blendState);
void SetDepthStencilAttachmentFormat(nxt::TextureFormat format);
void SetDepthStencilState(DepthStencilStateBase* depthStencilState); void SetDepthStencilState(DepthStencilStateBase* depthStencilState);
void SetPrimitiveTopology(nxt::PrimitiveTopology primitiveTopology); void SetPrimitiveTopology(nxt::PrimitiveTopology primitiveTopology);
void SetIndexFormat(nxt::IndexFormat format); void SetIndexFormat(nxt::IndexFormat format);
void SetInputState(InputStateBase* inputState); void SetInputState(InputStateBase* inputState);
void SetSubpass(RenderPassBase* renderPass, uint32_t subpass);
private: private:
friend class RenderPipelineBase; friend class RenderPipelineBase;
@ -75,8 +85,10 @@ namespace backend {
nxt::IndexFormat mIndexFormat = nxt::IndexFormat::Uint32; nxt::IndexFormat mIndexFormat = nxt::IndexFormat::Uint32;
std::bitset<kMaxColorAttachments> mBlendStatesSet; std::bitset<kMaxColorAttachments> mBlendStatesSet;
std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates; std::array<Ref<BlendStateBase>, kMaxColorAttachments> mBlendStates;
Ref<RenderPassBase> mRenderPass; std::bitset<kMaxColorAttachments> mColorAttachmentsSet;
uint32_t mSubpass; std::array<nxt::TextureFormat, kMaxColorAttachments> mColorAttachmentFormats;
bool mDepthStencilFormatSet = false;
nxt::TextureFormat mDepthStencilFormat;
}; };
} // namespace backend } // namespace backend

View File

@ -267,6 +267,10 @@ namespace backend {
TextureViewBase::TextureViewBase(TextureViewBuilder* builder) : mTexture(builder->mTexture) { TextureViewBase::TextureViewBase(TextureViewBuilder* builder) : mTexture(builder->mTexture) {
} }
const TextureBase* TextureViewBase::GetTexture() const {
return mTexture.Get();
}
TextureBase* TextureViewBase::GetTexture() { TextureBase* TextureViewBase::GetTexture() {
return mTexture.Get(); return mTexture.Get();
} }

View File

@ -99,6 +99,7 @@ namespace backend {
public: public:
TextureViewBase(TextureViewBuilder* builder); TextureViewBase(TextureViewBuilder* builder);
const TextureBase* GetTexture() const;
TextureBase* GetTexture(); TextureBase* GetTexture();
private: private:

View File

@ -68,11 +68,6 @@ namespace backend {
using BackendType = typename BackendTraits::DeviceType; using BackendType = typename BackendTraits::DeviceType;
}; };
template <typename BackendTraits>
struct ToBackendTraits<FramebufferBase, BackendTraits> {
using BackendType = typename BackendTraits::FramebufferType;
};
template <typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<InputStateBase, BackendTraits> { struct ToBackendTraits<InputStateBase, BackendTraits> {
using BackendType = typename BackendTraits::InputStateType; using BackendType = typename BackendTraits::InputStateType;
@ -89,8 +84,8 @@ namespace backend {
}; };
template <typename BackendTraits> template <typename BackendTraits>
struct ToBackendTraits<RenderPassBase, BackendTraits> { struct ToBackendTraits<RenderPassInfoBase, BackendTraits> {
using BackendType = typename BackendTraits::RenderPassType; using BackendType = typename BackendTraits::RenderPassInfoType;
}; };
template <typename BackendTraits> template <typename BackendTraits>

View File

@ -21,9 +21,9 @@
#include "backend/d3d12/ComputePipelineD3D12.h" #include "backend/d3d12/ComputePipelineD3D12.h"
#include "backend/d3d12/D3D12Backend.h" #include "backend/d3d12/D3D12Backend.h"
#include "backend/d3d12/DescriptorHeapAllocator.h" #include "backend/d3d12/DescriptorHeapAllocator.h"
#include "backend/d3d12/FramebufferD3D12.h"
#include "backend/d3d12/InputStateD3D12.h" #include "backend/d3d12/InputStateD3D12.h"
#include "backend/d3d12/PipelineLayoutD3D12.h" #include "backend/d3d12/PipelineLayoutD3D12.h"
#include "backend/d3d12/RenderPassInfoD3D12.h"
#include "backend/d3d12/RenderPipelineD3D12.h" #include "backend/d3d12/RenderPipelineD3D12.h"
#include "backend/d3d12/ResourceAllocator.h" #include "backend/d3d12/ResourceAllocator.h"
#include "backend/d3d12/SamplerD3D12.h" #include "backend/d3d12/SamplerD3D12.h"
@ -255,10 +255,6 @@ namespace backend { namespace d3d12 {
RenderPipeline* lastRenderPipeline = nullptr; RenderPipeline* lastRenderPipeline = nullptr;
PipelineLayout* lastLayout = nullptr; PipelineLayout* lastLayout = nullptr;
RenderPass* currentRenderPass = nullptr;
Framebuffer* currentFramebuffer = nullptr;
uint32_t currentSubpass = 0;
while (mCommands.NextCommandId(&type)) { while (mCommands.NextCommandId(&type)) {
switch (type) { switch (type) {
case Command::BeginComputePass: { case Command::BeginComputePass: {
@ -269,26 +265,10 @@ namespace backend { namespace d3d12 {
case Command::BeginRenderPass: { case Command::BeginRenderPass: {
BeginRenderPassCmd* beginRenderPassCmd = BeginRenderPassCmd* beginRenderPassCmd =
mCommands.NextCommand<BeginRenderPassCmd>(); mCommands.NextCommand<BeginRenderPassCmd>();
currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get()); RenderPassInfo* info = ToBackend(beginRenderPassCmd->info.Get());
currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
currentSubpass = 0;
uint32_t width = currentFramebuffer->GetWidth(); RenderPassInfo::OMSetRenderTargetArgs args =
uint32_t height = currentFramebuffer->GetHeight(); info->GetSubpassOMSetRenderTargetArgs();
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);
if (args.dsv.ptr) { if (args.dsv.ptr) {
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE, commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE,
&args.dsv); &args.dsv);
@ -297,47 +277,44 @@ namespace backend { namespace d3d12 {
nullptr); nullptr);
} }
// Clear framebuffer attachments as needed // Clear framebuffer attachments as needed and transition to render target
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) { for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
uint32_t attachmentSlot = subpass.colorAttachments[location]; auto& attachmentInfo = info->GetColorAttachment(i);
const auto& attachmentInfo = Texture* texture = ToBackend(attachmentInfo.view->GetTexture());
currentRenderPass->GetAttachmentInfo(attachmentSlot);
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 // It's already validated that this texture is either frozen to the correct
// usage, or not frozen. // usage, or not frozen.
if (!texture->IsFrozen()) { if (!texture->IsFrozen()) {
texture->TransitionUsageImpl(texture->GetUsage(), usage); texture->TransitionUsageImpl(texture->GetUsage(),
texture->UpdateUsageInternal(usage); nxt::TextureUsageBit::OutputAttachment);
texture->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
} }
// Only perform load op on first use
if (attachmentInfo.firstSubpass == currentSubpass) {
// Load op - color // Load op - color
if (attachmentInfo.colorLoadOp == nxt::LoadOp::Clear) { if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
auto handle = currentFramebuffer->GetRTVDescriptor(attachmentSlot); D3D12_CPU_DESCRIPTOR_HANDLE handle = info->GetRTVDescriptor(i);
const auto& clear = commandList->ClearRenderTargetView(
currentFramebuffer->GetClearColor(attachmentSlot); handle, attachmentInfo.clearColor.data(), 0, nullptr);
commandList->ClearRenderTargetView(handle, clear.color, 0, nullptr);
}
} }
} }
if (subpass.depthStencilAttachmentSet) { if (info->HasDepthStencilAttachment()) {
uint32_t attachmentSlot = subpass.depthStencilAttachment; auto& attachmentInfo = info->GetDepthStencilAttachment();
const auto& attachmentInfo = Texture* texture = ToBackend(attachmentInfo.view->GetTexture());
currentRenderPass->GetAttachmentInfo(attachmentSlot);
// 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);
}
// Only perform load op on first use
if (attachmentInfo.firstSubpass == currentSubpass) {
// Load op - depth/stencil // Load op - depth/stencil
bool doDepthClear = TextureFormatHasDepth(attachmentInfo.format) && bool doDepthClear = TextureFormatHasDepth(texture->GetFormat()) &&
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear); (attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
bool doStencilClear = bool doStencilClear = TextureFormatHasStencil(texture->GetFormat()) &&
TextureFormatHasStencil(attachmentInfo.format) &&
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear); (attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
D3D12_CLEAR_FLAGS clearFlags = {}; D3D12_CLEAR_FLAGS clearFlags = {};
@ -347,18 +324,29 @@ namespace backend { namespace d3d12 {
if (doStencilClear) { if (doStencilClear) {
clearFlags |= D3D12_CLEAR_FLAG_STENCIL; clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
} }
if (clearFlags) { if (clearFlags) {
auto handle = currentFramebuffer->GetDSVDescriptor(attachmentSlot); auto handle = info->GetDSVDescriptor();
const auto& clear =
currentFramebuffer->GetClearDepthStencil(attachmentSlot);
// TODO(kainino@chromium.org): investigate: should the NXT clear // TODO(kainino@chromium.org): investigate: should the NXT clear
// stencil type be uint8_t? // stencil type be uint8_t?
uint8_t clearStencil = static_cast<uint8_t>(clear.stencil); uint8_t clearStencil =
commandList->ClearDepthStencilView(handle, clearFlags, clear.depth, static_cast<uint8_t>(attachmentInfo.clearStencil);
commandList->ClearDepthStencilView(handle, clearFlags,
attachmentInfo.clearDepth,
clearStencil, 0, nullptr); 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}; static constexpr std::array<float, 4> defaultBlendFactor = {0, 0, 0, 0};
commandList->OMSetBlendFactor(&defaultBlendFactor[0]); commandList->OMSetBlendFactor(&defaultBlendFactor[0]);
@ -485,11 +473,6 @@ namespace backend { namespace d3d12 {
mCommands.NextCommand<EndRenderPassCmd>(); mCommands.NextCommand<EndRenderPassCmd>();
} break; } break;
case Command::EndRenderSubpass: {
mCommands.NextCommand<EndRenderSubpassCmd>();
currentSubpass += 1;
} break;
case Command::SetComputePipeline: { case Command::SetComputePipeline: {
SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>(); SetComputePipelineCmd* cmd = mCommands.NextCommand<SetComputePipelineCmd>();
ComputePipeline* pipeline = ToBackend(cmd->pipeline).Get(); ComputePipeline* pipeline = ToBackend(cmd->pipeline).Get();

View File

@ -23,11 +23,11 @@
#include "backend/d3d12/ComputePipelineD3D12.h" #include "backend/d3d12/ComputePipelineD3D12.h"
#include "backend/d3d12/DepthStencilStateD3D12.h" #include "backend/d3d12/DepthStencilStateD3D12.h"
#include "backend/d3d12/DescriptorHeapAllocator.h" #include "backend/d3d12/DescriptorHeapAllocator.h"
#include "backend/d3d12/FramebufferD3D12.h"
#include "backend/d3d12/InputStateD3D12.h" #include "backend/d3d12/InputStateD3D12.h"
#include "backend/d3d12/NativeSwapChainImplD3D12.h" #include "backend/d3d12/NativeSwapChainImplD3D12.h"
#include "backend/d3d12/PipelineLayoutD3D12.h" #include "backend/d3d12/PipelineLayoutD3D12.h"
#include "backend/d3d12/QueueD3D12.h" #include "backend/d3d12/QueueD3D12.h"
#include "backend/d3d12/RenderPassInfoD3D12.h"
#include "backend/d3d12/RenderPipelineD3D12.h" #include "backend/d3d12/RenderPipelineD3D12.h"
#include "backend/d3d12/ResourceAllocator.h" #include "backend/d3d12/ResourceAllocator.h"
#include "backend/d3d12/ResourceUploader.h" #include "backend/d3d12/ResourceUploader.h"
@ -282,9 +282,6 @@ namespace backend { namespace d3d12 {
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) { DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
return new DepthStencilState(this, builder); return new DepthStencilState(this, builder);
} }
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
return new Framebuffer(this, builder);
}
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) { InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(this, builder); return new InputState(this, builder);
} }
@ -294,8 +291,8 @@ namespace backend { namespace d3d12 {
QueueBase* Device::CreateQueue(QueueBuilder* builder) { QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(this, builder); return new Queue(this, builder);
} }
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) { RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
return new RenderPass(this, builder); return new RenderPassInfo(this, builder);
} }
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) { RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder); return new RenderPipeline(builder);
@ -316,10 +313,4 @@ namespace backend { namespace d3d12 {
return new TextureView(builder); return new TextureView(builder);
} }
// RenderPass
RenderPass::RenderPass(Device* device, RenderPassBuilder* builder)
: RenderPassBase(builder), mDevice(device) {
}
}} // namespace backend::d3d12 }} // namespace backend::d3d12

View File

@ -19,7 +19,6 @@
#include "backend/DepthStencilState.h" #include "backend/DepthStencilState.h"
#include "backend/Device.h" #include "backend/Device.h"
#include "backend/RenderPass.h"
#include "backend/ToBackend.h" #include "backend/ToBackend.h"
#include "backend/d3d12/d3d12_platform.h" #include "backend/d3d12/d3d12_platform.h"
#include "common/SerialQueue.h" #include "common/SerialQueue.h"
@ -35,11 +34,10 @@ namespace backend { namespace d3d12 {
class ComputePipeline; class ComputePipeline;
class DepthStencilState; class DepthStencilState;
class Device; class Device;
class Framebuffer;
class InputState; class InputState;
class PipelineLayout; class PipelineLayout;
class Queue; class Queue;
class RenderPass; class RenderPassInfo;
class RenderPipeline; class RenderPipeline;
class Sampler; class Sampler;
class ShaderModule; class ShaderModule;
@ -63,11 +61,10 @@ namespace backend { namespace d3d12 {
using ComputePipelineType = ComputePipeline; using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState; using DepthStencilStateType = DepthStencilState;
using DeviceType = Device; using DeviceType = Device;
using FramebufferType = Framebuffer;
using InputStateType = InputState; using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout; using PipelineLayoutType = PipelineLayout;
using QueueType = Queue; using QueueType = Queue;
using RenderPassType = RenderPass; using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline; using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler; using SamplerType = Sampler;
using ShaderModuleType = ShaderModule; using ShaderModuleType = ShaderModule;
@ -97,11 +94,10 @@ namespace backend { namespace d3d12 {
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override; CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override; ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override; DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override; InputStateBase* CreateInputState(InputStateBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override; PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override; QueueBase* CreateQueue(QueueBuilder* builder) override;
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override; RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override; RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override; SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override; ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
@ -155,14 +151,6 @@ namespace backend { namespace d3d12 {
SerialQueue<ComPtr<IUnknown>> mUsedComObjectRefs; SerialQueue<ComPtr<IUnknown>> mUsedComObjectRefs;
}; };
class RenderPass : public RenderPassBase {
public:
RenderPass(Device* device, RenderPassBuilder* builder);
private:
Device* mDevice;
};
}} // namespace backend::d3d12 }} // namespace backend::d3d12
#endif // BACKEND_D3D12_D3D12BACKEND_H_ #endif // BACKEND_D3D12_D3D12BACKEND_H_

View File

@ -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

View File

@ -20,10 +20,10 @@
#include "backend/d3d12/ComputePipelineD3D12.h" #include "backend/d3d12/ComputePipelineD3D12.h"
#include "backend/d3d12/D3D12Backend.h" #include "backend/d3d12/D3D12Backend.h"
#include "backend/d3d12/DepthStencilStateD3D12.h" #include "backend/d3d12/DepthStencilStateD3D12.h"
#include "backend/d3d12/FramebufferD3D12.h"
#include "backend/d3d12/InputStateD3D12.h" #include "backend/d3d12/InputStateD3D12.h"
#include "backend/d3d12/PipelineLayoutD3D12.h" #include "backend/d3d12/PipelineLayoutD3D12.h"
#include "backend/d3d12/QueueD3D12.h" #include "backend/d3d12/QueueD3D12.h"
#include "backend/d3d12/RenderPassInfoD3D12.h"
#include "backend/d3d12/RenderPipelineD3D12.h" #include "backend/d3d12/RenderPipelineD3D12.h"
#include "backend/d3d12/SamplerD3D12.h" #include "backend/d3d12/SamplerD3D12.h"
#include "backend/d3d12/ShaderModuleD3D12.h" #include "backend/d3d12/ShaderModuleD3D12.h"

View File

@ -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

View File

@ -12,10 +12,10 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#ifndef BACKEND_D3D12_FRAMEBUFFERD3D12_H_ #ifndef BACKEND_D3D12_RENDERPASSINFOD3D12_H_
#define BACKEND_D3D12_FRAMEBUFFERD3D12_H_ #define BACKEND_D3D12_RENDERPASSINFOD3D12_H_
#include "backend/Framebuffer.h" #include "backend/RenderPassInfo.h"
#include "backend/d3d12/DescriptorHeapAllocator.h" #include "backend/d3d12/DescriptorHeapAllocator.h"
#include "backend/d3d12/d3d12_platform.h" #include "backend/d3d12/d3d12_platform.h"
@ -28,7 +28,7 @@ namespace backend { namespace d3d12 {
class Device; class Device;
class Framebuffer : public FramebufferBase { class RenderPassInfo : public RenderPassInfoBase {
public: public:
struct OMSetRenderTargetArgs { struct OMSetRenderTargetArgs {
unsigned int numRTVs = 0; unsigned int numRTVs = 0;
@ -36,20 +36,17 @@ namespace backend { namespace d3d12 {
D3D12_CPU_DESCRIPTOR_HANDLE dsv = {}; D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
}; };
Framebuffer(Device* device, FramebufferBuilder* builder); RenderPassInfo(Device* device, RenderPassInfoBuilder* builder);
OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs(uint32_t subpassIndex); OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs();
D3D12_CPU_DESCRIPTOR_HANDLE GetRTVDescriptor(uint32_t attachmentSlot); D3D12_CPU_DESCRIPTOR_HANDLE GetRTVDescriptor(uint32_t attachmentSlot);
D3D12_CPU_DESCRIPTOR_HANDLE GetDSVDescriptor(uint32_t attachmentSlot); D3D12_CPU_DESCRIPTOR_HANDLE GetDSVDescriptor();
private: private:
Device* mDevice = nullptr; Device* mDevice = nullptr;
DescriptorHeapHandle mRtvHeap = {}; DescriptorHeapHandle mRtvHeap = {};
DescriptorHeapHandle mDsvHeap = {}; DescriptorHeapHandle mDsvHeap = {};
// Indices into either the RTV or DSV heap, depending on texture format.
std::vector<uint32_t> mAttachmentHeapIndices;
}; };
}} // namespace backend::d3d12 }} // namespace backend::d3d12
#endif // BACKEND_D3D12_FRAMEBUFFERD3D12_H_ #endif // BACKEND_D3D12_RENDERPASSINFOD3D12_H_

View File

@ -136,26 +136,16 @@ namespace backend { namespace d3d12 {
descriptor.RasterizerState.ForcedSampleCount = 0; descriptor.RasterizerState.ForcedSampleCount = 0;
descriptor.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; descriptor.RasterizerState.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF;
RenderPass* renderPass = ToBackend(GetRenderPass()); if (HasDepthStencilAttachment()) {
auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass()); descriptor.DSVFormat = D3D12TextureFormat(GetDepthStencilFormat());
if (subpassInfo.depthStencilAttachmentSet) {
const auto& attachmentInfo =
renderPass->GetAttachmentInfo(subpassInfo.depthStencilAttachment);
descriptor.DSVFormat = D3D12TextureFormat(attachmentInfo.format);
} }
unsigned int attachmentCount = 0; for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
for (unsigned int attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) { descriptor.RTVFormats[i] = D3D12TextureFormat(GetColorAttachmentFormat(i));
uint32_t attachment = subpassInfo.colorAttachments[attachmentSlot]; descriptor.BlendState.RenderTarget[i] =
const auto& attachmentInfo = renderPass->GetAttachmentInfo(attachment); ToBackend(GetBlendState(i))->GetD3D12BlendDesc();
descriptor.RTVFormats[attachmentSlot] = D3D12TextureFormat(attachmentInfo.format);
descriptor.BlendState.RenderTarget[attachmentSlot] =
ToBackend(GetBlendState(attachmentSlot))->GetD3D12BlendDesc();
attachmentCount = attachmentSlot + 1;
} }
descriptor.NumRenderTargets = attachmentCount; descriptor.NumRenderTargets = static_cast<uint32_t>(GetColorAttachmentsMask().count());
descriptor.BlendState.AlphaToCoverageEnable = FALSE; descriptor.BlendState.AlphaToCoverageEnable = FALSE;
descriptor.BlendState.IndependentBlendEnable = TRUE; descriptor.BlendState.IndependentBlendEnable = TRUE;

View File

@ -35,9 +35,6 @@ namespace backend { namespace metal {
id<MTLComputeCommandEncoder> compute = nil; id<MTLComputeCommandEncoder> compute = nil;
id<MTLRenderCommandEncoder> render = nil; id<MTLRenderCommandEncoder> render = nil;
RenderPass* currentRenderPass = nullptr;
Framebuffer* currentFramebuffer = nullptr;
void EnsureNoBlitEncoder() { void EnsureNoBlitEncoder() {
ASSERT(render == nil); ASSERT(render == nil);
ASSERT(compute == nil); ASSERT(compute == nil);
@ -67,59 +64,46 @@ namespace backend { namespace metal {
compute = nil; // This will be autoreleased. compute = nil; // This will be autoreleased.
} }
void BeginSubpass(id<MTLCommandBuffer> commandBuffer, uint32_t subpass) { void BeginRenderPass(id<MTLCommandBuffer> commandBuffer, RenderPassInfo* info) {
ASSERT(currentRenderPass);
if (render != nil) { if (render != nil) {
[render endEncoding]; [render endEncoding];
render = nil; // This will be autoreleased. render = nil; // This will be autoreleased.
} }
const auto& info = currentRenderPass->GetSubpassInfo(subpass);
MTLRenderPassDescriptor* descriptor = MTLRenderPassDescriptor* descriptor =
[MTLRenderPassDescriptor renderPassDescriptor]; [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); for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
auto texture = ToBackend(textureView->GetTexture())->GetMTLTexture(); auto& attachmentInfo = info->GetColorAttachment(i);
bool isFirstUse = attachmentInfo.firstSubpass == subpass; if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
bool shouldClearOnFirstUse = attachmentInfo.colorLoadOp == nxt::LoadOp::Clear; descriptor.colorAttachments[i].loadAction = MTLLoadActionClear;
if (isFirstUse && shouldClearOnFirstUse) { descriptor.colorAttachments[i].clearColor = MTLClearColorMake(
auto clearValue = currentFramebuffer->GetClearColor(location); attachmentInfo.clearColor[0], attachmentInfo.clearColor[1],
descriptor.colorAttachments[location].loadAction = MTLLoadActionClear; attachmentInfo.clearColor[2], attachmentInfo.clearColor[3]);
descriptor.colorAttachments[location].clearColor =
MTLClearColorMake(clearValue.color[0], clearValue.color[1],
clearValue.color[2], clearValue.color[3]);
} else { } else {
descriptor.colorAttachments[location].loadAction = MTLLoadActionLoad; descriptor.colorAttachments[i].loadAction = MTLLoadActionLoad;
} }
descriptor.colorAttachments[location].texture = texture; descriptor.colorAttachments[i].texture =
descriptor.colorAttachments[location].storeAction = MTLStoreActionStore; 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); if (info->HasDepthStencilAttachment()) {
id<MTLTexture> texture = ToBackend(textureView->GetTexture())->GetMTLTexture(); auto& attachmentInfo = info->GetDepthStencilAttachment();
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
bool isFirstUse = attachmentInfo.firstSubpass == subpass; id<MTLTexture> texture =
const auto& clearValues = currentFramebuffer->GetClearDepthStencil(attachment); ToBackend(attachmentInfo.view->GetTexture())->GetMTLTexture();
nxt::TextureFormat format = attachmentInfo.view->GetTexture()->GetFormat();
if (TextureFormatHasDepth(format)) { if (TextureFormatHasDepth(format)) {
descriptor.depthAttachment.texture = texture; descriptor.depthAttachment.texture = texture;
descriptor.depthAttachment.storeAction = MTLStoreActionStore; descriptor.depthAttachment.storeAction = MTLStoreActionStore;
bool shouldClearDepthOnFirstUse = if (attachmentInfo.depthLoadOp == nxt::LoadOp::Clear) {
attachmentInfo.depthLoadOp == nxt::LoadOp::Clear;
if (isFirstUse && shouldClearDepthOnFirstUse) {
descriptor.depthAttachment.loadAction = MTLLoadActionClear; descriptor.depthAttachment.loadAction = MTLLoadActionClear;
descriptor.depthAttachment.clearDepth = clearValues.depth; descriptor.depthAttachment.clearDepth = attachmentInfo.clearDepth;
} else { } else {
descriptor.depthAttachment.loadAction = MTLLoadActionLoad; descriptor.depthAttachment.loadAction = MTLLoadActionLoad;
} }
@ -129,11 +113,9 @@ namespace backend { namespace metal {
descriptor.stencilAttachment.texture = texture; descriptor.stencilAttachment.texture = texture;
descriptor.stencilAttachment.storeAction = MTLStoreActionStore; descriptor.stencilAttachment.storeAction = MTLStoreActionStore;
bool shouldClearStencilOnFirstUse = if (attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear) {
attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear;
if (isFirstUse && shouldClearStencilOnFirstUse) {
descriptor.stencilAttachment.loadAction = MTLLoadActionClear; descriptor.stencilAttachment.loadAction = MTLLoadActionClear;
descriptor.stencilAttachment.clearStencil = clearValues.stencil; descriptor.stencilAttachment.clearStencil = attachmentInfo.clearStencil;
} else { } else {
descriptor.stencilAttachment.loadAction = MTLLoadActionLoad; descriptor.stencilAttachment.loadAction = MTLLoadActionLoad;
} }
@ -144,7 +126,7 @@ namespace backend { namespace metal {
// TODO(cwallez@chromium.org): does any state need to be reset? // TODO(cwallez@chromium.org): does any state need to be reset?
} }
void EndSubpass() { void EndRenderPass() {
ASSERT(render != nil); ASSERT(render != nil);
[render endEncoding]; [render endEncoding];
render = nil; // This will be autoreleased. render = nil; // This will be autoreleased.
@ -174,7 +156,6 @@ namespace backend { namespace metal {
PerStage<std::array<uint32_t, kMaxPushConstants>> pushConstants; PerStage<std::array<uint32_t, kMaxPushConstants>> pushConstants;
uint32_t currentSubpass = 0;
while (mCommands.NextCommandId(&type)) { while (mCommands.NextCommandId(&type)) {
switch (type) { switch (type) {
case Command::BeginComputePass: { case Command::BeginComputePass: {
@ -190,15 +171,11 @@ namespace backend { namespace metal {
case Command::BeginRenderPass: { case Command::BeginRenderPass: {
BeginRenderPassCmd* beginRenderPassCmd = BeginRenderPassCmd* beginRenderPassCmd =
mCommands.NextCommand<BeginRenderPassCmd>(); mCommands.NextCommand<BeginRenderPassCmd>();
encoders.currentRenderPass = ToBackend(beginRenderPassCmd->renderPass.Get());
encoders.currentFramebuffer = ToBackend(beginRenderPassCmd->framebuffer.Get());
encoders.EnsureNoBlitEncoder();
currentSubpass = 0;
} break;
case Command::BeginRenderSubpass: { RenderPassInfo* info = ToBackend(beginRenderPassCmd->info.Get());
mCommands.NextCommand<BeginRenderSubpassCmd>();
encoders.BeginSubpass(commandBuffer, currentSubpass); encoders.EnsureNoBlitEncoder();
encoders.BeginRenderPass(commandBuffer, info);
pushConstants[nxt::ShaderStage::Vertex].fill(0); pushConstants[nxt::ShaderStage::Vertex].fill(0);
pushConstants[nxt::ShaderStage::Fragment].fill(0); pushConstants[nxt::ShaderStage::Fragment].fill(0);
@ -325,12 +302,7 @@ namespace backend { namespace metal {
case Command::EndRenderPass: { case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>(); mCommands.NextCommand<EndRenderPassCmd>();
} break; encoders.EndRenderPass();
case Command::EndRenderSubpass: {
mCommands.NextCommand<EndRenderSubpassCmd>();
encoders.EndSubpass();
currentSubpass += 1;
} break; } break;
case Command::SetComputePipeline: { case Command::SetComputePipeline: {

View File

@ -20,9 +20,8 @@
#include "backend/BindGroup.h" #include "backend/BindGroup.h"
#include "backend/BindGroupLayout.h" #include "backend/BindGroupLayout.h"
#include "backend/Device.h" #include "backend/Device.h"
#include "backend/Framebuffer.h"
#include "backend/Queue.h" #include "backend/Queue.h"
#include "backend/RenderPass.h" #include "backend/RenderPassInfo.h"
#include "backend/ToBackend.h" #include "backend/ToBackend.h"
#include "common/Serial.h" #include "common/Serial.h"
@ -45,7 +44,7 @@ namespace backend { namespace metal {
class InputState; class InputState;
class PipelineLayout; class PipelineLayout;
class Queue; class Queue;
class RenderPass; class RenderPassInfo;
class RenderPipeline; class RenderPipeline;
class Sampler; class Sampler;
class ShaderModule; class ShaderModule;
@ -63,11 +62,10 @@ namespace backend { namespace metal {
using ComputePipelineType = ComputePipeline; using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState; using DepthStencilStateType = DepthStencilState;
using DeviceType = Device; using DeviceType = Device;
using FramebufferType = Framebuffer;
using InputStateType = InputState; using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout; using PipelineLayoutType = PipelineLayout;
using QueueType = Queue; using QueueType = Queue;
using RenderPassType = RenderPass; using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline; using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler; using SamplerType = Sampler;
using ShaderModuleType = ShaderModule; using ShaderModuleType = ShaderModule;
@ -98,10 +96,9 @@ namespace backend { namespace metal {
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override; ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override; DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override; InputStateBase* CreateInputState(InputStateBuilder* builder) override;
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override; PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override; QueueBase* CreateQueue(QueueBuilder* builder) override;
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override; RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override; RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override; SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override; ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
@ -143,12 +140,6 @@ namespace backend { namespace metal {
BindGroupLayout(BindGroupLayoutBuilder* builder); BindGroupLayout(BindGroupLayoutBuilder* builder);
}; };
class Framebuffer : public FramebufferBase {
public:
Framebuffer(FramebufferBuilder* builder);
~Framebuffer();
};
class Queue : public QueueBase { class Queue : public QueueBase {
public: public:
Queue(QueueBuilder* builder); Queue(QueueBuilder* builder);
@ -163,10 +154,10 @@ namespace backend { namespace metal {
id<MTLCommandQueue> mCommandQueue = nil; id<MTLCommandQueue> mCommandQueue = nil;
}; };
class RenderPass : public RenderPassBase { class RenderPassInfo : public RenderPassInfoBase {
public: public:
RenderPass(RenderPassBuilder* builder); RenderPassInfo(RenderPassInfoBuilder* builder);
~RenderPass(); ~RenderPassInfo();
}; };
}} // namespace backend::metal }} // namespace backend::metal

View File

@ -101,9 +101,6 @@ namespace backend { namespace metal {
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) { DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
return new DepthStencilState(builder); return new DepthStencilState(builder);
} }
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
return new Framebuffer(builder);
}
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) { InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder); return new InputState(builder);
} }
@ -113,8 +110,8 @@ namespace backend { namespace metal {
QueueBase* Device::CreateQueue(QueueBuilder* builder) { QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(builder); return new Queue(builder);
} }
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) { RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
return new RenderPass(builder); return new RenderPassInfo(builder);
} }
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) { RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder); return new RenderPipeline(builder);
@ -202,14 +199,6 @@ namespace backend { namespace metal {
: BindGroupLayoutBase(builder) { : BindGroupLayoutBase(builder) {
} }
// Framebuffer
Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
}
Framebuffer::~Framebuffer() {
}
// Queue // Queue
Queue::Queue(QueueBuilder* builder) : QueueBase(builder) { Queue::Queue(QueueBuilder* builder) : QueueBase(builder) {
@ -240,10 +229,10 @@ namespace backend { namespace metal {
// RenderPass // RenderPass
RenderPass::RenderPass(RenderPassBuilder* builder) : RenderPassBase(builder) { RenderPassInfo::RenderPassInfo(RenderPassInfoBuilder* builder) : RenderPassInfoBase(builder) {
} }
RenderPass::~RenderPass() { RenderPassInfo::~RenderPassInfo() {
} }
}} // namespace backend::metal }} // namespace backend::metal

View File

@ -92,24 +92,17 @@ namespace backend { namespace metal {
} }
} }
RenderPass* renderPass = ToBackend(GetRenderPass()); if (HasDepthStencilAttachment()) {
auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass()); // TODO(kainino@chromium.org): Handle depth-only and stencil-only formats.
nxt::TextureFormat depthStencilFormat = GetDepthStencilFormat();
if (subpassInfo.depthStencilAttachmentSet) { descriptor.depthAttachmentPixelFormat = MetalPixelFormat(depthStencilFormat);
const auto& attachmentInfo = descriptor.stencilAttachmentPixelFormat = MetalPixelFormat(depthStencilFormat);
renderPass->GetAttachmentInfo(subpassInfo.depthStencilAttachment);
descriptor.depthAttachmentPixelFormat = MetalPixelFormat(attachmentInfo.format);
descriptor.stencilAttachmentPixelFormat = MetalPixelFormat(attachmentInfo.format);
} }
for (unsigned int attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) { for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
uint32_t attachment = subpassInfo.colorAttachments[attachmentSlot]; descriptor.colorAttachments[i].pixelFormat =
const auto& attachmentInfo = renderPass->GetAttachmentInfo(attachment); MetalPixelFormat(GetColorAttachmentFormat(i));
ToBackend(GetBlendState(i))->ApplyBlendState(descriptor.colorAttachments[i]);
descriptor.colorAttachments[attachmentSlot].pixelFormat =
MetalPixelFormat(attachmentInfo.format);
ToBackend(GetBlendState(attachmentSlot))
->ApplyBlendState(descriptor.colorAttachments[attachmentSlot]);
} }
descriptor.inputPrimitiveTopology = MTLInputPrimitiveTopology(GetPrimitiveTopology()); descriptor.inputPrimitiveTopology = MTLInputPrimitiveTopology(GetPrimitiveTopology());

View File

@ -60,9 +60,6 @@ namespace backend { namespace null {
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) { DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
return new DepthStencilState(builder); return new DepthStencilState(builder);
} }
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
return new Framebuffer(builder);
}
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) { InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder); return new InputState(builder);
} }
@ -72,8 +69,8 @@ namespace backend { namespace null {
QueueBase* Device::CreateQueue(QueueBuilder* builder) { QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(builder); return new Queue(builder);
} }
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) { RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
return new RenderPass(builder); return new RenderPassInfo(builder);
} }
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) { RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder); return new RenderPipeline(builder);

View File

@ -25,11 +25,10 @@
#include "backend/ComputePipeline.h" #include "backend/ComputePipeline.h"
#include "backend/DepthStencilState.h" #include "backend/DepthStencilState.h"
#include "backend/Device.h" #include "backend/Device.h"
#include "backend/Framebuffer.h"
#include "backend/InputState.h" #include "backend/InputState.h"
#include "backend/PipelineLayout.h" #include "backend/PipelineLayout.h"
#include "backend/Queue.h" #include "backend/Queue.h"
#include "backend/RenderPass.h" #include "backend/RenderPassInfo.h"
#include "backend/RenderPipeline.h" #include "backend/RenderPipeline.h"
#include "backend/Sampler.h" #include "backend/Sampler.h"
#include "backend/ShaderModule.h" #include "backend/ShaderModule.h"
@ -48,11 +47,10 @@ namespace backend { namespace null {
using ComputePipeline = ComputePipelineBase; using ComputePipeline = ComputePipelineBase;
using DepthStencilState = DepthStencilStateBase; using DepthStencilState = DepthStencilStateBase;
class Device; class Device;
using Framebuffer = FramebufferBase;
using InputState = InputStateBase; using InputState = InputStateBase;
using PipelineLayout = PipelineLayoutBase; using PipelineLayout = PipelineLayoutBase;
class Queue; class Queue;
using RenderPass = RenderPassBase; using RenderPassInfo = RenderPassInfoBase;
using RenderPipeline = RenderPipelineBase; using RenderPipeline = RenderPipelineBase;
using Sampler = SamplerBase; using Sampler = SamplerBase;
using ShaderModule = ShaderModuleBase; using ShaderModule = ShaderModuleBase;
@ -70,11 +68,10 @@ namespace backend { namespace null {
using ComputePipelineType = ComputePipeline; using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState; using DepthStencilStateType = DepthStencilState;
using DeviceType = Device; using DeviceType = Device;
using FramebufferType = Framebuffer;
using InputStateType = InputState; using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout; using PipelineLayoutType = PipelineLayout;
using QueueType = Queue; using QueueType = Queue;
using RenderPassType = RenderPass; using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline; using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler; using SamplerType = Sampler;
using ShaderModuleType = ShaderModule; using ShaderModuleType = ShaderModule;
@ -106,11 +103,10 @@ namespace backend { namespace null {
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override; CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override; ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override; DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override; InputStateBase* CreateInputState(InputStateBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override; PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override; QueueBase* CreateQueue(QueueBuilder* builder) override;
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override; RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override; RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override; SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override; ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;

View File

@ -254,9 +254,6 @@ namespace backend { namespace opengl {
PushConstantTracker pushConstants; PushConstantTracker pushConstants;
InputBufferTracker inputBuffers; InputBufferTracker inputBuffers;
RenderPass* currentRenderPass = nullptr;
Framebuffer* currentFramebuffer = nullptr;
uint32_t currentSubpass = 0;
GLuint currentFBO = 0; GLuint currentFBO = 0;
while (mCommands.NextCommandId(&type)) { while (mCommands.NextCommandId(&type)) {
@ -268,13 +265,8 @@ namespace backend { namespace opengl {
case Command::BeginRenderPass: { case Command::BeginRenderPass: {
auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>(); auto* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
currentRenderPass = ToBackend(cmd->renderPass.Get()); RenderPassInfo* info = ToBackend(cmd->info.Get());
currentFramebuffer = ToBackend(cmd->framebuffer.Get());
currentSubpass = 0;
} break;
case Command::BeginRenderSubpass: {
mCommands.NextCommand<BeginRenderSubpassCmd>();
pushConstants.OnBeginPass(); pushConstants.OnBeginPass();
inputBuffers.OnBeginPass(); inputBuffers.OnBeginPass();
@ -292,8 +284,6 @@ namespace backend { namespace opengl {
glGenFramebuffers(1, &currentFBO); glGenFramebuffers(1, &currentFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
const auto& subpass = currentRenderPass->GetSubpassInfo(currentSubpass);
// Mapping from attachmentSlot to GL framebuffer // Mapping from attachmentSlot to GL framebuffer
// attachment points. Defaults to zero (GL_NONE). // attachment points. Defaults to zero (GL_NONE).
std::array<GLenum, kMaxColorAttachments> drawBuffers = {}; std::array<GLenum, kMaxColorAttachments> drawBuffers = {};
@ -301,17 +291,15 @@ namespace backend { namespace opengl {
// Construct GL framebuffer // Construct GL framebuffer
unsigned int attachmentCount = 0; unsigned int attachmentCount = 0;
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) { for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
uint32_t attachment = subpass.colorAttachments[location]; TextureViewBase* textureView = info->GetColorAttachment(i).view.Get();
auto textureView = currentFramebuffer->GetTextureView(attachment);
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle(); GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
// Attach color buffers. // Attach color buffers.
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + location, glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i,
GL_TEXTURE_2D, texture, 0); GL_TEXTURE_2D, texture, 0);
drawBuffers[location] = GL_COLOR_ATTACHMENT0 + location; drawBuffers[i] = GL_COLOR_ATTACHMENT0 + i;
attachmentCount = location + 1; attachmentCount = i + 1;
// TODO(kainino@chromium.org): the color clears (later in // TODO(kainino@chromium.org): the color clears (later in
// this function) may be undefined for non-normalized integer formats. // this function) may be undefined for non-normalized integer formats.
@ -323,10 +311,8 @@ namespace backend { namespace opengl {
} }
glDrawBuffers(attachmentCount, drawBuffers.data()); glDrawBuffers(attachmentCount, drawBuffers.data());
if (subpass.depthStencilAttachmentSet) { if (info->HasDepthStencilAttachment()) {
uint32_t attachmentSlot = subpass.depthStencilAttachment; TextureViewBase* textureView = info->GetDepthStencilAttachment().view.Get();
auto textureView = currentFramebuffer->GetTextureView(attachmentSlot);
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle(); GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
nxt::TextureFormat format = textureView->GetTexture()->GetFormat(); nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
@ -354,52 +340,39 @@ namespace backend { namespace opengl {
// Clear framebuffer attachments as needed // Clear framebuffer attachments as needed
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) { for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
uint32_t attachmentSlot = subpass.colorAttachments[location]; const auto& attachmentInfo = info->GetColorAttachment(i);
const auto& attachmentInfo =
currentRenderPass->GetAttachmentInfo(attachmentSlot);
// Only perform load op on first use
if (attachmentInfo.firstSubpass == currentSubpass) {
// Load op - color // Load op - color
if (attachmentInfo.colorLoadOp == nxt::LoadOp::Clear) { if (attachmentInfo.loadOp == nxt::LoadOp::Clear) {
const auto& clear = currentFramebuffer->GetClearColor(location); glClearBufferfv(GL_COLOR, i, attachmentInfo.clearColor.data());
glClearBufferfv(GL_COLOR, location, clear.color);
}
} }
} }
if (subpass.depthStencilAttachmentSet) { if (info->HasDepthStencilAttachment()) {
uint32_t attachmentSlot = subpass.depthStencilAttachment; const auto& attachmentInfo = info->GetDepthStencilAttachment();
const auto& attachmentInfo = nxt::TextureFormat attachmentFormat =
currentRenderPass->GetAttachmentInfo(attachmentSlot); attachmentInfo.view->GetTexture()->GetFormat();
// Only perform load op on first use
if (attachmentInfo.firstSubpass == currentSubpass) {
// Load op - depth/stencil // Load op - depth/stencil
const auto& clear = currentFramebuffer->GetClearDepthStencil( bool doDepthClear = TextureFormatHasDepth(attachmentFormat) &&
subpass.depthStencilAttachment);
bool doDepthClear = TextureFormatHasDepth(attachmentInfo.format) &&
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear); (attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
bool doStencilClear = bool doStencilClear = TextureFormatHasStencil(attachmentFormat) &&
TextureFormatHasStencil(attachmentInfo.format) &&
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear); (attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
if (doDepthClear && doStencilClear) { if (doDepthClear && doStencilClear) {
glClearBufferfi(GL_DEPTH_STENCIL, 0, clear.depth, clear.stencil); glClearBufferfi(GL_DEPTH_STENCIL, 0, attachmentInfo.clearDepth,
attachmentInfo.clearStencil);
} else if (doDepthClear) { } else if (doDepthClear) {
glClearBufferfv(GL_DEPTH, 0, &clear.depth); glClearBufferfv(GL_DEPTH, 0, &attachmentInfo.clearDepth);
} else if (doStencilClear) { } else if (doStencilClear) {
const GLint clearStencil = clear.stencil; const GLint clearStencil = attachmentInfo.clearStencil;
glClearBufferiv(GL_STENCIL, 0, &clearStencil); glClearBufferiv(GL_STENCIL, 0, &clearStencil);
} }
} }
}
glBlendColor(0, 0, 0, 0); glBlendColor(0, 0, 0, 0);
glViewport(0, 0, currentFramebuffer->GetWidth(), glViewport(0, 0, info->GetWidth(), info->GetHeight());
currentFramebuffer->GetHeight()); glScissor(0, 0, info->GetWidth(), info->GetHeight());
glScissor(0, 0, currentFramebuffer->GetWidth(),
currentFramebuffer->GetHeight());
} break; } break;
case Command::CopyBufferToBuffer: { case Command::CopyBufferToBuffer: {
@ -530,13 +503,8 @@ namespace backend { namespace opengl {
case Command::EndRenderPass: { case Command::EndRenderPass: {
mCommands.NextCommand<EndRenderPassCmd>(); mCommands.NextCommand<EndRenderPassCmd>();
} break;
case Command::EndRenderSubpass: {
mCommands.NextCommand<EndRenderSubpassCmd>();
glDeleteFramebuffers(1, &currentFBO); glDeleteFramebuffers(1, &currentFBO);
currentFBO = 0; currentFBO = 0;
currentSubpass += 1;
} break; } break;
case Command::SetComputePipeline: { case Command::SetComputePipeline: {

View File

@ -73,17 +73,14 @@ namespace backend { namespace opengl {
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) { InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder); return new InputState(builder);
} }
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
return new Framebuffer(builder);
}
PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) { PipelineLayoutBase* Device::CreatePipelineLayout(PipelineLayoutBuilder* builder) {
return new PipelineLayout(builder); return new PipelineLayout(builder);
} }
QueueBase* Device::CreateQueue(QueueBuilder* builder) { QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(builder); return new Queue(builder);
} }
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) { RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
return new RenderPass(builder); return new RenderPassInfo(builder);
} }
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) { RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder); return new RenderPipeline(builder);
@ -118,11 +115,6 @@ namespace backend { namespace opengl {
: BindGroupLayoutBase(builder) { : BindGroupLayoutBase(builder) {
} }
// Framebuffer
Framebuffer::Framebuffer(FramebufferBuilder* builder) : FramebufferBase(builder) {
}
// Queue // Queue
Queue::Queue(QueueBuilder* builder) : QueueBase(builder) { 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 }} // namespace backend::opengl

View File

@ -23,10 +23,9 @@
#include "backend/Buffer.h" #include "backend/Buffer.h"
#include "backend/DepthStencilState.h" #include "backend/DepthStencilState.h"
#include "backend/Device.h" #include "backend/Device.h"
#include "backend/Framebuffer.h"
#include "backend/InputState.h" #include "backend/InputState.h"
#include "backend/Queue.h" #include "backend/Queue.h"
#include "backend/RenderPass.h" #include "backend/RenderPassInfo.h"
#include "backend/ToBackend.h" #include "backend/ToBackend.h"
#include "glad/glad.h" #include "glad/glad.h"
@ -42,12 +41,11 @@ namespace backend { namespace opengl {
class ComputePipeline; class ComputePipeline;
class DepthStencilState; class DepthStencilState;
class Device; class Device;
class Framebuffer;
class InputState; class InputState;
class PersistentPipelineState; class PersistentPipelineState;
class PipelineLayout; class PipelineLayout;
class Queue; class Queue;
class RenderPass; class RenderPassInfo;
class RenderPipeline; class RenderPipeline;
class Sampler; class Sampler;
class ShaderModule; class ShaderModule;
@ -65,11 +63,10 @@ namespace backend { namespace opengl {
using ComputePipelineType = ComputePipeline; using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState; using DepthStencilStateType = DepthStencilState;
using DeviceType = Device; using DeviceType = Device;
using FramebufferType = Framebuffer;
using InputStateType = InputState; using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout; using PipelineLayoutType = PipelineLayout;
using QueueType = Queue; using QueueType = Queue;
using RenderPassType = RenderPass; using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline; using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler; using SamplerType = Sampler;
using ShaderModuleType = ShaderModule; using ShaderModuleType = ShaderModule;
@ -95,10 +92,9 @@ namespace backend { namespace opengl {
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override; ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override; DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override; InputStateBase* CreateInputState(InputStateBuilder* builder) override;
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override; PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override; QueueBase* CreateQueue(QueueBuilder* builder) override;
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override; RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override; RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override; SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override; ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
@ -119,11 +115,6 @@ namespace backend { namespace opengl {
BindGroupLayout(BindGroupLayoutBuilder* builder); BindGroupLayout(BindGroupLayoutBuilder* builder);
}; };
class Framebuffer : public FramebufferBase {
public:
Framebuffer(FramebufferBuilder* builder);
};
class Queue : public QueueBase { class Queue : public QueueBase {
public: public:
Queue(QueueBuilder* builder); Queue(QueueBuilder* builder);
@ -132,9 +123,9 @@ namespace backend { namespace opengl {
void Submit(uint32_t numCommands, CommandBuffer* const* commands); void Submit(uint32_t numCommands, CommandBuffer* const* commands);
}; };
class RenderPass : public RenderPassBase { class RenderPassInfo : public RenderPassInfoBase {
public: public:
RenderPass(RenderPassBuilder* builder); RenderPassInfo(RenderPassInfoBuilder* builder);
}; };
}} // namespace backend::opengl }} // namespace backend::opengl

View File

@ -60,10 +60,7 @@ namespace backend { namespace opengl {
auto depthStencilState = ToBackend(GetDepthStencilState()); auto depthStencilState = ToBackend(GetDepthStencilState());
depthStencilState->ApplyNow(persistentPipelineState); depthStencilState->ApplyNow(persistentPipelineState);
RenderPass* renderPass = ToBackend(GetRenderPass()); for (uint32_t attachmentSlot : IterateBitSet(GetColorAttachmentsMask())) {
auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
for (uint32_t attachmentSlot : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
ToBackend(GetBlendState(attachmentSlot))->ApplyNow(attachmentSlot); ToBackend(GetBlendState(attachmentSlot))->ApplyNow(attachmentSlot);
} }
} }

View File

@ -18,9 +18,8 @@
#include "backend/vulkan/BindGroupVk.h" #include "backend/vulkan/BindGroupVk.h"
#include "backend/vulkan/BufferVk.h" #include "backend/vulkan/BufferVk.h"
#include "backend/vulkan/ComputePipelineVk.h" #include "backend/vulkan/ComputePipelineVk.h"
#include "backend/vulkan/FramebufferVk.h"
#include "backend/vulkan/PipelineLayoutVk.h" #include "backend/vulkan/PipelineLayoutVk.h"
#include "backend/vulkan/RenderPassVk.h" #include "backend/vulkan/RenderPassInfoVk.h"
#include "backend/vulkan/RenderPipelineVk.h" #include "backend/vulkan/RenderPipelineVk.h"
#include "backend/vulkan/TextureVk.h" #include "backend/vulkan/TextureVk.h"
#include "backend/vulkan/VulkanBackend.h" #include "backend/vulkan/VulkanBackend.h"
@ -184,43 +183,32 @@ namespace backend { namespace vulkan {
case Command::BeginRenderPass: { case Command::BeginRenderPass: {
BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>(); BeginRenderPassCmd* cmd = mCommands.NextCommand<BeginRenderPassCmd>();
Framebuffer* framebuffer = ToBackend(cmd->framebuffer.Get()); RenderPassInfo* info = ToBackend(cmd->info.Get());
RenderPass* renderPass = ToBackend(cmd->renderPass.Get());
// NXT has an implicit transition to color attachment on subpasses. Transition // NXT has an implicit transition to color attachment on render passes.
// the attachments now before we start the render pass. // Transition the attachments now before we start the render pass.
for (uint32_t i = 0; i < renderPass->GetAttachmentCount(); ++i) { for (uint32_t i : IterateBitSet(info->GetColorAttachmentMask())) {
Texture* attachment = 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(), attachment->RecordBarrier(commands, attachment->GetUsage(),
nxt::TextureUsageBit::OutputAttachment); nxt::TextureUsageBit::OutputAttachment);
attachment->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment); attachment->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
} }
}
if (info->HasDepthStencilAttachment()) {
Texture* attachment =
ToBackend(info->GetDepthStencilAttachment().view->GetTexture());
ASSERT(renderPass->GetSubpassCount() == 1); if (!(attachment->GetUsage() & nxt::TextureUsageBit::OutputAttachment)) {
ASSERT(renderPass->GetAttachmentCount() <= kMaxColorAttachments + 1); attachment->RecordBarrier(commands, attachment->GetUsage(),
nxt::TextureUsageBit::OutputAttachment);
attachment->UpdateUsageInternal(nxt::TextureUsageBit::OutputAttachment);
}
}
std::array<VkClearValue, kMaxColorAttachments + 1> clearValues; info->RecordBeginRenderPass(commands);
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);
// Set all the dynamic state just in case. // Set all the dynamic state just in case.
device->fn.CmdSetLineWidth(commands, 1.0f); device->fn.CmdSetLineWidth(commands, 1.0f);
@ -228,32 +216,6 @@ namespace backend { namespace vulkan {
device->fn.CmdSetStencilReference(commands, VK_STENCIL_FRONT_AND_BACK, 0); 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] = { float blendConstants[4] = {
0.0f, 0.0f,
0.0f, 0.0f,
@ -261,6 +223,25 @@ namespace backend { namespace vulkan {
0.0f, 0.0f,
}; };
device->fn.CmdSetBlendConstants(commands, blendConstants); 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; } break;
case Command::DrawArrays: { case Command::DrawArrays: {
@ -285,11 +266,6 @@ namespace backend { namespace vulkan {
device->fn.CmdEndRenderPass(commands); device->fn.CmdEndRenderPass(commands);
} break; } break;
case Command::EndRenderSubpass: {
mCommands.NextCommand<EndRenderSubpassCmd>();
// Do nothing because the single subpass is ended in vkEndRenderPass
} break;
case Command::BeginComputePass: { case Command::BeginComputePass: {
mCommands.NextCommand<BeginComputePassCmd>(); mCommands.NextCommand<BeginComputePassCmd>();
descriptorSets.OnBeginPass(); descriptorSets.OnBeginPass();

View File

@ -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

View File

@ -19,10 +19,9 @@
#include "backend/vulkan/CommandBufferVk.h" #include "backend/vulkan/CommandBufferVk.h"
#include "backend/vulkan/ComputePipelineVk.h" #include "backend/vulkan/ComputePipelineVk.h"
#include "backend/vulkan/DepthStencilStateVk.h" #include "backend/vulkan/DepthStencilStateVk.h"
#include "backend/vulkan/FramebufferVk.h"
#include "backend/vulkan/InputStateVk.h" #include "backend/vulkan/InputStateVk.h"
#include "backend/vulkan/PipelineLayoutVk.h" #include "backend/vulkan/PipelineLayoutVk.h"
#include "backend/vulkan/RenderPassVk.h" #include "backend/vulkan/RenderPassInfoVk.h"
#include "backend/vulkan/RenderPipelineVk.h" #include "backend/vulkan/RenderPipelineVk.h"
#include "backend/vulkan/SamplerVk.h" #include "backend/vulkan/SamplerVk.h"
#include "backend/vulkan/ShaderModuleVk.h" #include "backend/vulkan/ShaderModuleVk.h"

View File

@ -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

View File

@ -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_

View File

@ -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

View File

@ -12,27 +12,28 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#ifndef BACKEND_VULKAN_FRAMEBUFFERVK_H_ #ifndef BACKEND_VULKAN_RENDERPASSINFOVK_H_
#define BACKEND_VULKAN_FRAMEBUFFERVK_H_ #define BACKEND_VULKAN_RENDERPASSINFOVK_H_
#include "backend/Framebuffer.h" #include "backend/RenderPassInfo.h"
#include "common/vulkan_platform.h" #include "common/vulkan_platform.h"
namespace backend { namespace vulkan { namespace backend { namespace vulkan {
class Framebuffer : public FramebufferBase { class Device;
public:
Framebuffer(FramebufferBuilder* builder);
~Framebuffer();
VkFramebuffer GetHandle() const; class RenderPassInfo : public RenderPassInfoBase {
void FillClearValues(VkClearValue* values); public:
RenderPassInfo(RenderPassInfoBuilder* builder);
// Compute all the arguments for, and record the vkCmdBeginRenderPass command.
void RecordBeginRenderPass(VkCommandBuffer commands);
private: private:
VkFramebuffer mHandle = VK_NULL_HANDLE; Device* mDevice = nullptr;
}; };
}} // namespace backend::vulkan }} // namespace backend::vulkan
#endif // BACKEND_VULKAN_FRAMEBUFFERVK_H_ #endif // BACKEND_VULKAN_RENDERPASSINFOVK_H_

View File

@ -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

View File

@ -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_

View File

@ -19,7 +19,8 @@
#include "backend/vulkan/FencedDeleter.h" #include "backend/vulkan/FencedDeleter.h"
#include "backend/vulkan/InputStateVk.h" #include "backend/vulkan/InputStateVk.h"
#include "backend/vulkan/PipelineLayoutVk.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/ShaderModuleVk.h"
#include "backend/vulkan/VulkanBackend.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 // Initialize the "blend state info" that will be chained in the "create info" from the data
// pre-computed in the BlendState // pre-computed in the BlendState
const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(GetSubPass());
std::array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments; std::array<VkPipelineColorBlendAttachmentState, kMaxColorAttachments> colorBlendAttachments;
for (uint32_t i : IterateBitSet(subpassInfo.colorAttachmentsSet)) { for (uint32_t i : IterateBitSet(GetColorAttachmentsMask())) {
colorBlendAttachments[i] = ToBackend(GetBlendState(i))->GetState(); colorBlendAttachments[i] = ToBackend(GetBlendState(i))->GetState();
} }
VkPipelineColorBlendStateCreateInfo colorBlend; VkPipelineColorBlendStateCreateInfo colorBlend;
@ -147,7 +146,7 @@ namespace backend { namespace vulkan {
colorBlend.logicOpEnable = VK_FALSE; colorBlend.logicOpEnable = VK_FALSE;
colorBlend.logicOp = VK_LOGIC_OP_CLEAR; colorBlend.logicOp = VK_LOGIC_OP_CLEAR;
// TODO(cwallez@chromium.org): Do we allow holes in the color attachments? // 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(); colorBlend.pAttachments = colorBlendAttachments.data();
// The blend constant is always dynamic so we fill in a dummy value // The blend constant is always dynamic so we fill in a dummy value
colorBlend.blendConstants[0] = 0.0f; colorBlend.blendConstants[0] = 0.0f;
@ -172,6 +171,24 @@ namespace backend { namespace vulkan {
dynamic.dynamicStateCount = sizeof(dynamicStates) / sizeof(dynamicStates[0]); dynamic.dynamicStateCount = sizeof(dynamicStates) / sizeof(dynamicStates[0]);
dynamic.pDynamicStates = dynamicStates; 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 // The create info chains in a bunch of things created on the stack here or inside state
// objects. // objects.
VkGraphicsPipelineCreateInfo createInfo; VkGraphicsPipelineCreateInfo createInfo;
@ -190,8 +207,8 @@ namespace backend { namespace vulkan {
createInfo.pColorBlendState = &colorBlend; createInfo.pColorBlendState = &colorBlend;
createInfo.pDynamicState = &dynamic; createInfo.pDynamicState = &dynamic;
createInfo.layout = ToBackend(GetLayout())->GetHandle(); createInfo.layout = ToBackend(GetLayout())->GetHandle();
createInfo.renderPass = ToBackend(GetRenderPass())->GetHandle(); createInfo.renderPass = renderPass;
createInfo.subpass = GetSubPass(); createInfo.subpass = 0;
createInfo.basePipelineHandle = VK_NULL_HANDLE; createInfo.basePipelineHandle = VK_NULL_HANDLE;
createInfo.basePipelineIndex = -1; createInfo.basePipelineIndex = -1;

View File

@ -24,11 +24,11 @@
#include "backend/vulkan/ComputePipelineVk.h" #include "backend/vulkan/ComputePipelineVk.h"
#include "backend/vulkan/DepthStencilStateVk.h" #include "backend/vulkan/DepthStencilStateVk.h"
#include "backend/vulkan/FencedDeleter.h" #include "backend/vulkan/FencedDeleter.h"
#include "backend/vulkan/FramebufferVk.h"
#include "backend/vulkan/InputStateVk.h" #include "backend/vulkan/InputStateVk.h"
#include "backend/vulkan/NativeSwapChainImplVk.h" #include "backend/vulkan/NativeSwapChainImplVk.h"
#include "backend/vulkan/PipelineLayoutVk.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/RenderPipelineVk.h"
#include "backend/vulkan/SamplerVk.h" #include "backend/vulkan/SamplerVk.h"
#include "backend/vulkan/ShaderModuleVk.h" #include "backend/vulkan/ShaderModuleVk.h"
@ -146,6 +146,7 @@ namespace backend { namespace vulkan {
mDeleter = new FencedDeleter(this); mDeleter = new FencedDeleter(this);
mMapRequestTracker = new MapRequestTracker(this); mMapRequestTracker = new MapRequestTracker(this);
mMemoryAllocator = new MemoryAllocator(this); mMemoryAllocator = new MemoryAllocator(this);
mRenderPassCache = new RenderPassCache(this);
} }
Device::~Device() { Device::~Device() {
@ -189,6 +190,11 @@ namespace backend { namespace vulkan {
delete mMemoryAllocator; delete mMemoryAllocator;
mMemoryAllocator = nullptr; 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 // VkQueues are destroyed when the VkDevice is destroyed
if (mVkDevice != VK_NULL_HANDLE) { if (mVkDevice != VK_NULL_HANDLE) {
fn.DestroyDevice(mVkDevice, nullptr); fn.DestroyDevice(mVkDevice, nullptr);
@ -231,9 +237,6 @@ namespace backend { namespace vulkan {
DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) { DepthStencilStateBase* Device::CreateDepthStencilState(DepthStencilStateBuilder* builder) {
return new DepthStencilState(builder); return new DepthStencilState(builder);
} }
FramebufferBase* Device::CreateFramebuffer(FramebufferBuilder* builder) {
return new Framebuffer(builder);
}
InputStateBase* Device::CreateInputState(InputStateBuilder* builder) { InputStateBase* Device::CreateInputState(InputStateBuilder* builder) {
return new InputState(builder); return new InputState(builder);
} }
@ -243,8 +246,8 @@ namespace backend { namespace vulkan {
QueueBase* Device::CreateQueue(QueueBuilder* builder) { QueueBase* Device::CreateQueue(QueueBuilder* builder) {
return new Queue(builder); return new Queue(builder);
} }
RenderPassBase* Device::CreateRenderPass(RenderPassBuilder* builder) { RenderPassInfoBase* Device::CreateRenderPassInfo(RenderPassInfoBuilder* builder) {
return new RenderPass(builder); return new RenderPassInfo(builder);
} }
RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) { RenderPipelineBase* Device::CreateRenderPipeline(RenderPipelineBuilder* builder) {
return new RenderPipeline(builder); return new RenderPipeline(builder);
@ -325,6 +328,10 @@ namespace backend { namespace vulkan {
return mDeleter; return mDeleter;
} }
RenderPassCache* Device::GetRenderPassCache() const {
return mRenderPassCache;
}
Serial Device::GetSerial() const { Serial Device::GetSerial() const {
return mNextSerial; return mNextSerial;
} }

View File

@ -39,11 +39,10 @@ namespace backend { namespace vulkan {
class ComputePipeline; class ComputePipeline;
class DepthStencilState; class DepthStencilState;
class Device; class Device;
class Framebuffer;
class InputState; class InputState;
class PipelineLayout; class PipelineLayout;
class Queue; class Queue;
class RenderPass; class RenderPassInfo;
class RenderPipeline; class RenderPipeline;
class Sampler; class Sampler;
class ShaderModule; class ShaderModule;
@ -55,6 +54,7 @@ namespace backend { namespace vulkan {
class FencedDeleter; class FencedDeleter;
class MapRequestTracker; class MapRequestTracker;
class MemoryAllocator; class MemoryAllocator;
class RenderPassCache;
struct VulkanBackendTraits { struct VulkanBackendTraits {
using BindGroupType = BindGroup; using BindGroupType = BindGroup;
@ -66,11 +66,10 @@ namespace backend { namespace vulkan {
using ComputePipelineType = ComputePipeline; using ComputePipelineType = ComputePipeline;
using DepthStencilStateType = DepthStencilState; using DepthStencilStateType = DepthStencilState;
using DeviceType = Device; using DeviceType = Device;
using FramebufferType = Framebuffer;
using InputStateType = InputState; using InputStateType = InputState;
using PipelineLayoutType = PipelineLayout; using PipelineLayoutType = PipelineLayout;
using QueueType = Queue; using QueueType = Queue;
using RenderPassType = RenderPass; using RenderPassInfoType = RenderPassInfo;
using RenderPipelineType = RenderPipeline; using RenderPipelineType = RenderPipeline;
using SamplerType = Sampler; using SamplerType = Sampler;
using ShaderModuleType = ShaderModule; using ShaderModuleType = ShaderModule;
@ -103,6 +102,7 @@ namespace backend { namespace vulkan {
FencedDeleter* GetFencedDeleter() const; FencedDeleter* GetFencedDeleter() const;
MapRequestTracker* GetMapRequestTracker() const; MapRequestTracker* GetMapRequestTracker() const;
MemoryAllocator* GetMemoryAllocator() const; MemoryAllocator* GetMemoryAllocator() const;
RenderPassCache* GetRenderPassCache() const;
Serial GetSerial() const; Serial GetSerial() const;
@ -119,11 +119,10 @@ namespace backend { namespace vulkan {
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override; CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override; ComputePipelineBase* CreateComputePipeline(ComputePipelineBuilder* builder) override;
DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override; DepthStencilStateBase* CreateDepthStencilState(DepthStencilStateBuilder* builder) override;
FramebufferBase* CreateFramebuffer(FramebufferBuilder* builder) override;
InputStateBase* CreateInputState(InputStateBuilder* builder) override; InputStateBase* CreateInputState(InputStateBuilder* builder) override;
PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override; PipelineLayoutBase* CreatePipelineLayout(PipelineLayoutBuilder* builder) override;
QueueBase* CreateQueue(QueueBuilder* builder) override; QueueBase* CreateQueue(QueueBuilder* builder) override;
RenderPassBase* CreateRenderPass(RenderPassBuilder* builder) override; RenderPassInfoBase* CreateRenderPassInfo(RenderPassInfoBuilder* builder) override;
RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override; RenderPipelineBase* CreateRenderPipeline(RenderPipelineBuilder* builder) override;
SamplerBase* CreateSampler(SamplerBuilder* builder) override; SamplerBase* CreateSampler(SamplerBuilder* builder) override;
ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override; ShaderModuleBase* CreateShaderModule(ShaderModuleBuilder* builder) override;
@ -170,6 +169,7 @@ namespace backend { namespace vulkan {
FencedDeleter* mDeleter = nullptr; FencedDeleter* mDeleter = nullptr;
MapRequestTracker* mMapRequestTracker = nullptr; MapRequestTracker* mMapRequestTracker = nullptr;
MemoryAllocator* mMemoryAllocator = nullptr; MemoryAllocator* mMemoryAllocator = nullptr;
RenderPassCache* mRenderPassCache = nullptr;
VkFence GetUnusedFence(); VkFence GetUnusedFence();
void CheckPassedFences(); void CheckPassedFences();

View File

@ -48,13 +48,12 @@ list(APPEND UNITTEST_SOURCES
${VALIDATION_TESTS_DIR}/CopyCommandsValidationTests.cpp ${VALIDATION_TESTS_DIR}/CopyCommandsValidationTests.cpp
${VALIDATION_TESTS_DIR}/DepthStencilStateValidationTests.cpp ${VALIDATION_TESTS_DIR}/DepthStencilStateValidationTests.cpp
${VALIDATION_TESTS_DIR}/DynamicStateCommandValidationTests.cpp ${VALIDATION_TESTS_DIR}/DynamicStateCommandValidationTests.cpp
${VALIDATION_TESTS_DIR}/FramebufferValidationTests.cpp
${VALIDATION_TESTS_DIR}/InputStateValidationTests.cpp ${VALIDATION_TESTS_DIR}/InputStateValidationTests.cpp
${VALIDATION_TESTS_DIR}/PushConstantsValidationTests.cpp ${VALIDATION_TESTS_DIR}/PushConstantsValidationTests.cpp
${VALIDATION_TESTS_DIR}/VertexBufferValidationTests.cpp ${VALIDATION_TESTS_DIR}/RenderPassInfoValidationTests.cpp
${VALIDATION_TESTS_DIR}/RenderPassValidationTests.cpp
${VALIDATION_TESTS_DIR}/RenderPipelineValidationTests.cpp ${VALIDATION_TESTS_DIR}/RenderPipelineValidationTests.cpp
${VALIDATION_TESTS_DIR}/UsageValidationTests.cpp ${VALIDATION_TESTS_DIR}/UsageValidationTests.cpp
${VALIDATION_TESTS_DIR}/VertexBufferValidationTests.cpp
${VALIDATION_TESTS_DIR}/ValidationTest.cpp ${VALIDATION_TESTS_DIR}/ValidationTest.cpp
${VALIDATION_TESTS_DIR}/ValidationTest.h ${VALIDATION_TESTS_DIR}/ValidationTest.h
${TESTS_DIR}/UnittestsMain.cpp ${TESTS_DIR}/UnittestsMain.cpp

View File

@ -45,7 +45,7 @@ class BlendStateTest : public NXTTest {
.SetBindGroupLayout(0, bindGroupLayout) .SetBindGroupLayout(0, bindGroupLayout)
.GetResult(); .GetResult();
fb = utils::CreateBasicFramebuffer(device, kRTSize, kRTSize); renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
} }
struct TriangleSpec { struct TriangleSpec {
@ -69,14 +69,14 @@ class BlendStateTest : public NXTTest {
)"); )");
basePipeline = device.CreateRenderPipelineBuilder() basePipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(fb.renderPass, 0) .SetColorAttachmentFormat(0, renderPass.colorFormat)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.GetResult(); .GetResult();
testPipeline = device.CreateRenderPipelineBuilder() testPipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(fb.renderPass, 0) .SetColorAttachmentFormat(0, renderPass.colorFormat)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -112,11 +112,10 @@ 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 // 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) { 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() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
// First use the base pipeline to draw a triangle with no blending // First use the base pipeline to draw a triangle with no blending
.SetRenderPipeline(basePipeline) .SetRenderPipeline(basePipeline)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { base } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { base } })))
@ -127,14 +126,13 @@ class BlendStateTest : public NXTTest {
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { triangle.color } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { triangle.color } })))
.SetBlendColor(triangle.blendFactor[0], triangle.blendFactor[1], triangle.blendFactor[2], triangle.blendFactor[3]) .SetBlendColor(triangle.blendFactor[0], triangle.blendFactor[1], triangle.blendFactor[2], triangle.blendFactor[3])
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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 // 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); CheckBlendFactor(base, nxt::BlendFactor::One, colorFactor, nxt::BlendFactor::One, alphaFactor, tests);
} }
utils::BasicFramebuffer fb; utils::BasicRenderPass renderPass;
nxt::RenderPipeline basePipeline; nxt::RenderPipeline basePipeline;
nxt::RenderPipeline testPipeline; nxt::RenderPipeline testPipeline;
nxt::ShaderModule vsModule; nxt::ShaderModule vsModule;
@ -679,27 +677,25 @@ TEST_P(BlendStateTest, ColorWriteMaskBlendingDisabled) {
RGBA8 base(32, 64, 128, 192); RGBA8 base(32, 64, 128, 192);
RGBA8 expected(32, 0, 0, 0); RGBA8 expected(32, 0, 0, 0);
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(testPipeline) .SetRenderPipeline(testPipeline)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { base } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { base } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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 that independent blend states on render targets works
TEST_P(BlendStateTest, IndependentBlendState) { TEST_P(BlendStateTest, IndependentBlendState) {
std::array<nxt::Texture, 5> renderTargets; std::array<nxt::Texture, 4> renderTargets;
std::array<nxt::TextureView, 5> renderTargetViews; 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() renderTargets[i] = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D) .SetDimension(nxt::TextureDimension::e2D)
.SetExtent(kRTSize, kRTSize, 1) .SetExtent(kRTSize, kRTSize, 1)
@ -711,30 +707,11 @@ TEST_P(BlendStateTest, IndependentBlendState) {
renderTargetViews[i] = renderTargets[i].CreateTextureViewBuilder().GetResult(); renderTargetViews[i] = renderTargets[i].CreateTextureViewBuilder().GetResult();
} }
nxt::RenderPass renderpass = device.CreateRenderPassBuilder() nxt::RenderPassInfo renderpass = device.CreateRenderPassInfoBuilder()
.SetAttachmentCount(5) .SetColorAttachment(0, renderTargetViews[0], nxt::LoadOp::Clear)
.SetSubpassCount(1) .SetColorAttachment(1, renderTargetViews[1], nxt::LoadOp::Clear)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm) .SetColorAttachment(2, renderTargetViews[2], nxt::LoadOp::Clear)
.AttachmentSetFormat(1, nxt::TextureFormat::R8G8B8A8Unorm) .SetColorAttachment(3, renderTargetViews[3], nxt::LoadOp::Clear)
.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])
.GetResult(); .GetResult();
nxt::ShaderModule fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"( nxt::ShaderModule fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
@ -778,14 +755,20 @@ TEST_P(BlendStateTest, IndependentBlendState) {
} }; } };
basePipeline = device.CreateRenderPipelineBuilder() 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) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.GetResult(); .GetResult();
testPipeline = device.CreateRenderPipelineBuilder() 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) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -808,14 +791,13 @@ TEST_P(BlendStateTest, IndependentBlendState) {
RGBA8 expected2 = color2; RGBA8 expected2 = color2;
RGBA8 expected3 = min(color3, base); 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[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() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderpass)
.BeginRenderSubpass()
.SetRenderPipeline(basePipeline) .SetRenderPipeline(basePipeline)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 4>({ { base, base, base, base } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 4>({ { base, base, base, base } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
@ -823,58 +805,26 @@ TEST_P(BlendStateTest, IndependentBlendState) {
.SetRenderPipeline(testPipeline) .SetRenderPipeline(testPipeline)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 4>({ { color0, color1, color2, color3 } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 4>({ { color0, color1, color2, color3 } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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(expected0, renderTargets[0], kRTSize / 2, kRTSize / 2) << "Attachment slot 0 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(expected1, renderTargets[1], kRTSize / 2, kRTSize / 2) << "Attachment slot 1 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(expected2, renderTargets[2], kRTSize / 2, kRTSize / 2) << "Attachment slot 2 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(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 that the default blend color is correctly set at the beginning of every subpass
TEST_P(BlendStateTest, DefaultBlendColor) { 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() nxt::BlendState blendState = device.CreateBlendStateBuilder()
.SetBlendEnabled(true) .SetBlendEnabled(true)
.SetColorBlend(nxt::BlendOperation::Add, nxt::BlendFactor::BlendColor, nxt::BlendFactor::One) .SetColorBlend(nxt::BlendOperation::Add, nxt::BlendFactor::BlendColor, nxt::BlendFactor::One)
.SetAlphaBlend(nxt::BlendOperation::Add, nxt::BlendFactor::BlendColor, nxt::BlendFactor::One) .SetAlphaBlend(nxt::BlendOperation::Add, nxt::BlendFactor::BlendColor, nxt::BlendFactor::One)
.GetResult(); .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"( nxt::ShaderModule fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
#version 450 #version 450
layout(set = 0, binding = 0) uniform myBlock { layout(set = 0, binding = 0) uniform myBlock {
@ -889,29 +839,14 @@ TEST_P(BlendStateTest, DefaultBlendColor) {
)"); )");
basePipeline = device.CreateRenderPipelineBuilder() basePipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, renderPass.colorFormat)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.GetResult(); .GetResult();
testPipeline = device.CreateRenderPipelineBuilder() testPipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, renderPass.colorFormat)
.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)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "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) // Check that the initial blend color is (0,0,0,0)
{ {
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(basePipeline) .SetRenderPipeline(basePipeline)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.SetRenderPipeline(testPipeline) .SetRenderPipeline(testPipeline)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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 // Check that setting the blend color works
{ {
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(basePipeline) .SetRenderPipeline(basePipeline)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
@ -950,20 +882,18 @@ TEST_P(BlendStateTest, DefaultBlendColor) {
.SetBlendColor(1, 1, 1, 1) .SetBlendColor(1, 1, 1, 1)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(basePipeline) .SetRenderPipeline(basePipeline)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
@ -971,21 +901,20 @@ TEST_P(BlendStateTest, DefaultBlendColor) {
.SetBlendColor(1, 1, 1, 1) .SetBlendColor(1, 1, 1, 1)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass() .EndRenderPass()
.BeginRenderSubpass() .BeginRenderPass(renderPass.renderPassInfo)
.SetRenderPipeline(basePipeline2) .SetRenderPipeline(basePipeline)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(0, 0, 0, 0) } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.SetRenderPipeline(testPipeline2) .SetRenderPipeline(testPipeline)
.SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } }))) .SetBindGroup(0, MakeBindGroupForColors(std::array<RGBA8, 1>({ { RGBA8(255, 255, 255, 255) } })))
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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);
} }
} }

View File

@ -24,17 +24,6 @@ class DepthStencilStateTest : public NXTTest {
void SetUp() override { void SetUp() override {
NXTTest::SetUp(); 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() renderTarget = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D) .SetDimension(nxt::TextureDimension::e2D)
.SetExtent(kRTSize, kRTSize, 1) .SetExtent(kRTSize, kRTSize, 1)
@ -57,11 +46,9 @@ class DepthStencilStateTest : public NXTTest {
depthTextureView = depthTexture.CreateTextureViewBuilder().GetResult(); depthTextureView = depthTexture.CreateTextureViewBuilder().GetResult();
framebuffer = device.CreateFramebufferBuilder() renderpass = device.CreateRenderPassInfoBuilder()
.SetRenderPass(renderpass) .SetColorAttachment(0, renderTargetView, nxt::LoadOp::Clear)
.SetAttachment(0, renderTargetView) .SetDepthStencilAttachment(depthTextureView, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
.SetAttachment(1, depthTextureView)
.SetDimensions(kRTSize, kRTSize)
.GetResult(); .GetResult();
vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"( vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
@ -207,8 +194,7 @@ class DepthStencilStateTest : public NXTTest {
}; };
renderTarget.TransitionUsage(nxt::TextureUsageBit::OutputAttachment); renderTarget.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
builder.BeginRenderPass(renderpass, framebuffer) builder.BeginRenderPass(renderpass);
.BeginRenderSubpass();
for (size_t i = 0; i < testParams.size(); ++i) { for (size_t i = 0; i < testParams.size(); ++i) {
const TestSpec& test = testParams[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 // Create a pipeline for the triangles with the test spec's depth stencil state
nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder() nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetDepthStencilAttachmentFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -247,7 +234,6 @@ class DepthStencilStateTest : public NXTTest {
} }
nxt::CommandBuffer commands = builder nxt::CommandBuffer commands = builder
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
@ -261,12 +247,11 @@ class DepthStencilStateTest : public NXTTest {
DoTest(testParams, expected, expected); DoTest(testParams, expected, expected);
} }
nxt::RenderPass renderpass; nxt::RenderPassInfo renderpass;
nxt::Texture renderTarget; nxt::Texture renderTarget;
nxt::Texture depthTexture; nxt::Texture depthTexture;
nxt::TextureView renderTargetView; nxt::TextureView renderTargetView;
nxt::TextureView depthTextureView; nxt::TextureView depthTextureView;
nxt::Framebuffer framebuffer;
nxt::ShaderModule vsModule; nxt::ShaderModule vsModule;
nxt::ShaderModule fsModule; nxt::ShaderModule fsModule;
nxt::BindGroupLayout bindGroupLayout; nxt::BindGroupLayout bindGroupLayout;

View File

@ -23,30 +23,7 @@ class DrawElementsTest : public NXTTest {
void SetUp() override { void SetUp() override {
NXTTest::SetUp(); NXTTest::SetUp();
renderpass = device.CreateRenderPassBuilder() renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
.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();
nxt::InputState inputState = device.CreateInputStateBuilder() nxt::InputState inputState = device.CreateInputStateBuilder()
.SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex) .SetInput(0, 4 * sizeof(float), nxt::InputStepMode::Vertex)
@ -70,7 +47,7 @@ class DrawElementsTest : public NXTTest {
); );
pipeline = device.CreateRenderPipelineBuilder() pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, renderPass.colorFormat)
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleStrip) .SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleStrip)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -89,10 +66,7 @@ class DrawElementsTest : public NXTTest {
}); });
} }
nxt::RenderPass renderpass; utils::BasicRenderPass renderPass;
nxt::Texture renderTarget;
nxt::TextureView renderTargetView;
nxt::Framebuffer framebuffer;
nxt::RenderPipeline pipeline; nxt::RenderPipeline pipeline;
nxt::Buffer vertexBuffer; nxt::Buffer vertexBuffer;
nxt::Buffer indexBuffer; nxt::Buffer indexBuffer;
@ -101,20 +75,18 @@ class DrawElementsTest : public NXTTest {
uint32_t firstInstance, RGBA8 bottomLeftExpected, RGBA8 topRightExpected) { uint32_t firstInstance, RGBA8 bottomLeftExpected, RGBA8 topRightExpected) {
uint32_t zeroOffset = 0; uint32_t zeroOffset = 0;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset) .SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
.SetIndexBuffer(indexBuffer, 0) .SetIndexBuffer(indexBuffer, 0)
.DrawElements(indexCount, instanceCount, firstIndex, firstInstance) .DrawElements(indexCount, instanceCount, firstIndex, firstInstance)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); queue.Submit(1, &commands);
EXPECT_PIXEL_RGBA8_EQ(bottomLeftExpected, renderTarget, 1, 3); EXPECT_PIXEL_RGBA8_EQ(bottomLeftExpected, renderPass.color, 1, 3);
EXPECT_PIXEL_RGBA8_EQ(topRightExpected, renderTarget, 3, 1); EXPECT_PIXEL_RGBA8_EQ(topRightExpected, renderPass.color, 3, 1);
} }
}; };

View File

@ -24,36 +24,10 @@ class IndexFormatTest : public NXTTest {
void SetUp() override { void SetUp() override {
NXTTest::SetUp(); NXTTest::SetUp();
renderpass = device.CreateRenderPassBuilder() renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
.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();
} }
nxt::RenderPass renderpass; utils::BasicRenderPass renderPass;
nxt::Texture renderTarget;
nxt::TextureView renderTargetView;
nxt::Framebuffer framebuffer;
nxt::RenderPipeline MakeTestPipeline(nxt::IndexFormat format) { nxt::RenderPipeline MakeTestPipeline(nxt::IndexFormat format) {
nxt::InputState inputState = device.CreateInputStateBuilder() nxt::InputState inputState = device.CreateInputStateBuilder()
@ -78,7 +52,7 @@ class IndexFormatTest : public NXTTest {
); );
return device.CreateRenderPipelineBuilder() return device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, renderPass.colorFormat)
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleStrip) .SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleStrip)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -105,19 +79,17 @@ TEST_P(IndexFormatTest, Uint32) {
uint32_t zeroOffset = 0; uint32_t zeroOffset = 0;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset) .SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
.SetIndexBuffer(indexBuffer, 0) .SetIndexBuffer(indexBuffer, 0)
.DrawElements(3, 1, 0, 0) .DrawElements(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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 // Test that the Uint16 index format is correctly interpreted
@ -136,19 +108,17 @@ TEST_P(IndexFormatTest, Uint16) {
uint32_t zeroOffset = 0; uint32_t zeroOffset = 0;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset) .SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
.SetIndexBuffer(indexBuffer, 0) .SetIndexBuffer(indexBuffer, 0)
.DrawElements(3, 1, 0, 0) .DrawElements(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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 // 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; uint32_t zeroOffset = 0;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset) .SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
.SetIndexBuffer(indexBuffer, 0) .SetIndexBuffer(indexBuffer, 0)
.DrawElements(7, 1, 0, 0) .DrawElements(7, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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), renderPass.color, 190, 190); // A
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderTarget, 210, 210); // B EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 210, 210); // B
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderTarget, 210, 190); // C EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderPass.color, 210, 190); // C
} }
// Test use of primitive restart with an Uint16 index format // Test use of primitive restart with an Uint16 index format
@ -214,21 +182,19 @@ TEST_P(IndexFormatTest, Uint16PrimitiveRestart) {
uint32_t zeroOffset = 0; uint32_t zeroOffset = 0;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset) .SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
.SetIndexBuffer(indexBuffer, 0) .SetIndexBuffer(indexBuffer, 0)
.DrawElements(7, 1, 0, 0) .DrawElements(7, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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), renderPass.color, 190, 190); // A
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderTarget, 210, 210); // B EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), renderPass.color, 210, 210); // B
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 0, 0, 0), renderTarget, 210, 190); // C 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 // 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; uint32_t zeroOffset = 0;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline16) .SetRenderPipeline(pipeline16)
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset) .SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
.SetIndexBuffer(indexBuffer, 0) .SetIndexBuffer(indexBuffer, 0)
.SetRenderPipeline(pipeline32) .SetRenderPipeline(pipeline32)
.DrawElements(3, 1, 0, 0) .DrawElements(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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 // 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; uint32_t zeroOffset = 0;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetIndexBuffer(indexBuffer, 0) .SetIndexBuffer(indexBuffer, 0)
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset) .SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
.DrawElements(3, 1, 0, 0) .DrawElements(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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) NXT_INSTANTIATE_TEST(IndexFormatTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)

View File

@ -37,7 +37,7 @@ class InputStateTest : public NXTTest {
void SetUp() override { void SetUp() override {
NXTTest::SetUp(); NXTTest::SetUp();
fb = utils::CreateBasicFramebuffer(device, kRTSize, kRTSize); renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
} }
bool ShouldComponentBeDefault(VertexFormat format, int component) { bool ShouldComponentBeDefault(VertexFormat format, int component) {
@ -121,7 +121,7 @@ class InputStateTest : public NXTTest {
); );
return device.CreateRenderPipelineBuilder() return device.CreateRenderPipelineBuilder()
.SetSubpass(fb.renderPass, 0) .SetColorAttachmentFormat(0, renderPass.colorFormat)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetInputState(inputState) .SetInputState(inputState)
@ -168,9 +168,8 @@ class InputStateTest : public NXTTest {
nxt::CommandBufferBuilder builder = device.CreateCommandBufferBuilder(); nxt::CommandBufferBuilder builder = device.CreateCommandBufferBuilder();
fb.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment); renderPass.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
builder.BeginRenderPass(fb.renderPass, fb.framebuffer) builder.BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline); .SetRenderPipeline(pipeline);
uint32_t zeroOffset = 0; uint32_t zeroOffset = 0;
@ -180,7 +179,6 @@ class InputStateTest : public NXTTest {
nxt::CommandBuffer commands = builder nxt::CommandBuffer commands = builder
.DrawArrays(triangles * 3, instances, 0, 0) .DrawArrays(triangles * 3, instances, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
@ -193,15 +191,15 @@ class InputStateTest : public NXTTest {
unsigned int x = kRTCellOffset + kRTCellSize * triangle; unsigned int x = kRTCellOffset + kRTCellSize * triangle;
unsigned int y = kRTCellOffset + kRTCellSize * instance; unsigned int y = kRTCellOffset + kRTCellSize * instance;
if (triangle < triangles && instance < instances) { 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 { } 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 :) // Test compilation and usage of the fixture :)

View File

@ -147,30 +147,7 @@ class PrimitiveTopologyTest : public NXTTest {
void SetUp() override { void SetUp() override {
NXTTest::SetUp(); NXTTest::SetUp();
renderpass = device.CreateRenderPassBuilder() renderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
.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();
vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"( vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
#version 450 #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 // 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) { void DoTest(nxt::PrimitiveTopology primitiveTopology, const std::vector<LocationSpec> &locationSpecs) {
nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder() nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, renderPass.colorFormat)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetInputState(inputState) .SetInputState(inputState)
.SetPrimitiveTopology(primitiveTopology) .SetPrimitiveTopology(primitiveTopology)
.GetResult(); .GetResult();
renderTarget.TransitionUsage(nxt::TextureUsageBit::OutputAttachment); renderPass.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
static const uint32_t zeroOffset = 0; static const uint32_t zeroOffset = 0;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset) .SetVertexBuffers(0, 1, &vertexBuffer, &zeroOffset)
.DrawArrays(6, 1, 0, 0) .DrawArrays(6, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
@ -234,16 +209,13 @@ class PrimitiveTopologyTest : public NXTTest {
for (size_t i = 0; i < locationSpec.count; ++i) { 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 // 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); 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; << "Expected (" << locationSpec.locations[i].x << ", " << locationSpec.locations[i].y << ") to be " << color;
} }
} }
} }
nxt::RenderPass renderpass; utils::BasicRenderPass renderPass;
nxt::Texture renderTarget;
nxt::TextureView renderTargetView;
nxt::Framebuffer framebuffer;
nxt::ShaderModule vsModule; nxt::ShaderModule vsModule;
nxt::ShaderModule fsModule; nxt::ShaderModule fsModule;
nxt::InputState inputState; nxt::InputState inputState;

View File

@ -160,8 +160,7 @@ class PushConstantTest: public NXTTest {
// The render pipeline adds one to the red channel for successful vertex push constant test // The render pipeline adds one to the red channel for successful vertex push constant test
// and adds one to green for the frgament test. // and adds one to green for the frgament test.
nxt::RenderPipeline MakeTestRenderPipeline(nxt::PipelineLayout& layout, nxt::RenderPass& renderPass, uint32_t subpass, nxt::RenderPipeline MakeTestRenderPipeline(nxt::PipelineLayout& layout, PushConstantSpec vsSpec, PushConstantSpec fsSpec) {
PushConstantSpec vsSpec, PushConstantSpec fsSpec) {
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, (R"( nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, (R"(
#version 450 #version 450
)" + MakePushConstantBlock(vsSpec) + R"( )" + MakePushConstantBlock(vsSpec) + R"(
@ -192,7 +191,7 @@ class PushConstantTest: public NXTTest {
.GetResult(); .GetResult();
return device.CreateRenderPipelineBuilder() return device.CreateRenderPipelineBuilder()
.SetSubpass(renderPass, subpass) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(layout) .SetLayout(layout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -233,63 +232,26 @@ TEST_P(PushConstantTest, ComputePassDefaultsToZero) {
EXPECT_BUFFER_U32_EQ(1, binding.resultBuffer, 0); EXPECT_BUFFER_U32_EQ(1, binding.resultBuffer, 0);
} }
// Test that push constants default to zero at the beginning of every render subpasses. // Test that push constants default to zero at the beginning of render passes.
TEST_P(PushConstantTest, RenderSubpassDefaultsToZero) { TEST_P(PushConstantTest, RenderPassDefaultsToZero) {
// Change the renderpass to be a two subpass renderpass just for this test. utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 1, 1);
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();
// Expect push constants to be zero in all draws of this test. // Expect push constants to be zero in all draws of this test.
PushConstantSpec allZeros = MakeAllZeroSpec(); PushConstantSpec allZeros = MakeAllZeroSpec();
nxt::PipelineLayout layout = MakeEmptyLayout(); nxt::PipelineLayout layout = MakeEmptyLayout();
nxt::RenderPipeline pipeline1 = MakeTestRenderPipeline(layout, renderPass, 0, MakeAllZeroSpec(), MakeAllZeroSpec()); nxt::RenderPipeline pipeline = MakeTestRenderPipeline(layout, MakeAllZeroSpec(), MakeAllZeroSpec());
nxt::RenderPipeline pipeline2 = MakeTestRenderPipeline(layout, renderPass, 1, MakeAllZeroSpec(), MakeAllZeroSpec());
uint32_t notZero = 42;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderPass, framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
// Test render push constants are set to zero by default. // Test render push constants are set to zero by default.
.SetRenderPipeline(pipeline1) .SetRenderPipeline(pipeline)
.DrawArrays(1, 1, 0, 0) .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, &notZero)
.EndRenderSubpass()
.BeginRenderSubpass()
.SetRenderPipeline(pipeline2)
.DrawArrays(1, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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. // Test setting push constants of various 32bit types.
@ -389,51 +351,47 @@ TEST_P(PushConstantTest, SeparateVertexAndFragmentConstants) {
PushConstantSpec vsSpec = {{Int, 1}}; PushConstantSpec vsSpec = {{Int, 1}};
PushConstantSpec fsSpec = {{Int, 2}}; 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::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 one = 1;
uint32_t two = 2; uint32_t two = 2;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, &one) .SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, &one)
.SetPushConstants(nxt::ShaderStageBit::Fragment, 0, 1, &two) .SetPushConstants(nxt::ShaderStageBit::Fragment, 0, 1, &two)
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.DrawArrays(1, 1, 0, 0) .DrawArrays(1, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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 // Try setting push constants for vertex and fragment stage simulteanously
TEST_P(PushConstantTest, SimultaneousVertexAndFragmentConstants) { TEST_P(PushConstantTest, SimultaneousVertexAndFragmentConstants) {
PushConstantSpec spec = {{Int, 2}}; 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::PipelineLayout layout = MakeEmptyLayout();
nxt::RenderPipeline pipeline = MakeTestRenderPipeline(layout, fb.renderPass, 0, spec, spec); nxt::RenderPipeline pipeline = MakeTestRenderPipeline(layout, spec, spec);
uint32_t two = 2; uint32_t two = 2;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, &two) .SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, &two)
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.DrawArrays(1, 1, 0, 0) .DrawArrays(1, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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) NXT_INSTANTIATE_TEST(PushConstantTest, MetalBackend, OpenGLBackend)

View File

@ -32,9 +32,9 @@ class DrawQuad {
.GetResult(); .GetResult();
} }
void Draw(const nxt::RenderPass& renderpass, nxt::CommandBufferBuilder* builder) { void Draw(nxt::CommandBufferBuilder* builder) {
auto renderPipeline = device->CreateRenderPipelineBuilder() auto renderPipeline = device->CreateRenderPipelineBuilder()
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -108,127 +108,63 @@ class RenderPassLoadOpTests : public NXTTest {
// Tests clearing, loading, and drawing into color attachments // Tests clearing, loading, and drawing into color attachments
TEST_P(RenderPassLoadOpTests, ColorClearThenLoadAndDraw) { 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 // Part 1: clear once, check to make sure it's cleared
auto renderpass1 = device.CreateRenderPassBuilder() auto renderPassClearZero = device.CreateRenderPassInfoBuilder()
.SetAttachmentCount(1) .SetColorAttachment(0, renderTargetView, nxt::LoadOp::Clear)
.SetSubpassCount(1) .SetColorAttachmentClearColor(0, 0.0f, 0.0f, 0.0f, 0.0f)
.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)
.GetResult(); .GetResult();
auto commands1 = device.CreateCommandBufferBuilder() auto commandsClearZero = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass1, framebuffer1) .BeginRenderPass(renderPassClearZero)
.BeginRenderSubpass()
// Clear should occur implicitly // Clear should occur implicitly
// Store should occur implicitly // Store should occur implicitly
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
framebuffer1.AttachmentSetClearColor(0, 0.0f, 0.0f, 0.0f, 0.0f); // zero auto renderPassClearGreen = device.CreateRenderPassInfoBuilder()
queue.Submit(1, &commands1); .SetColorAttachment(0, renderTargetView, nxt::LoadOp::Clear)
// Cleared to zero .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); 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, &commandsClearGreen);
queue.Submit(1, &commands1);
// Now cleared to green
EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize, kRTSize, 0); 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 // Part 2: draw a blue quad into the right half of the render target, and check result
auto renderpass2 = device.CreateRenderPassBuilder() auto renderPassLoad = device.CreateRenderPassInfoBuilder()
.SetAttachmentCount(1) .SetColorAttachment(0, renderTargetView, nxt::LoadOp::Load)
.SetSubpassCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Load)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult(); .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() auto builder = device.CreateCommandBufferBuilder()
.BeginRenderPass(renderpass2, framebuffer2) .BeginRenderPass(renderPassLoad)
.BeginRenderSubpass() // Load should occur implicitly
// Clear should occur implicitly
.Clone(); .Clone();
blueQuad.Draw(renderpass2, &builder); blueQuad.Draw(&builder);
commands2 = builder commandsLoad = builder
// Store should occur implicitly // Store should occur implicitly
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
} }
queue.Submit(1, &commands2); queue.Submit(1, &commandsLoad);
// Left half should still be green // Left half should still be green
EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize / 2, kRTSize, 0); EXPECT_TEXTURE_RGBA8_EQ(expectGreen.data(), renderTarget, 0, 0, kRTSize / 2, kRTSize, 0);
// Right half should now be blue // Right half should now be blue
EXPECT_TEXTURE_RGBA8_EQ(expectBlue.data(), renderTarget, kRTSize / 2, 0, kRTSize / 2, kRTSize, 0); 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) NXT_INSTANTIATE_TEST(RenderPassLoadOpTests, D3D12Backend, MetalBackend, OpenGLBackend)

View File

@ -40,8 +40,8 @@ class SamplerTest : public NXTTest {
protected: protected:
void SetUp() override { void SetUp() override {
NXTTest::SetUp(); NXTTest::SetUp();
mFB = utils::CreateBasicFramebuffer(device, kRTSize, kRTSize); mRenderPass = utils::CreateBasicRenderPass(device, kRTSize, kRTSize);
mFB.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment); mRenderPass.color.TransitionUsage(nxt::TextureUsageBit::OutputAttachment);
mBindGroupLayout = device.CreateBindGroupLayoutBuilder() mBindGroupLayout = device.CreateBindGroupLayoutBuilder()
.SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler, 0, 1) .SetBindingsType(nxt::ShaderStageBit::Fragment, nxt::BindingType::Sampler, 0, 1)
@ -76,7 +76,7 @@ protected:
)"); )");
mPipeline = device.CreateRenderPipelineBuilder() mPipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(mFB.renderPass, 0) .SetColorAttachmentFormat(0, mRenderPass.colorFormat)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -123,12 +123,10 @@ protected:
.GetResult(); .GetResult();
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(mFB.renderPass, mFB.framebuffer) .BeginRenderPass(mRenderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(mPipeline) .SetRenderPipeline(mPipeline)
.SetBindGroup(0, bindGroup) .SetBindGroup(0, bindGroup)
.DrawArrays(6, 1, 0, 0) .DrawArrays(6, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
@ -140,18 +138,18 @@ protected:
RGBA8 expectedV3(v.mExpected3, v.mExpected3, v.mExpected3, 255); RGBA8 expectedV3(v.mExpected3, v.mExpected3, v.mExpected3, 255);
RGBA8 black(0, 0, 0, 255); RGBA8 black(0, 0, 0, 255);
RGBA8 white(255, 255, 255, 255); RGBA8 white(255, 255, 255, 255);
EXPECT_PIXEL_RGBA8_EQ(black, mFB.color, 0, 0); EXPECT_PIXEL_RGBA8_EQ(black, mRenderPass.color, 0, 0);
EXPECT_PIXEL_RGBA8_EQ(white, mFB.color, 0, 1); EXPECT_PIXEL_RGBA8_EQ(white, mRenderPass.color, 0, 1);
EXPECT_PIXEL_RGBA8_EQ(white, mFB.color, 1, 0); EXPECT_PIXEL_RGBA8_EQ(white, mRenderPass.color, 1, 0);
EXPECT_PIXEL_RGBA8_EQ(black, mFB.color, 1, 1); EXPECT_PIXEL_RGBA8_EQ(black, mRenderPass.color, 1, 1);
EXPECT_PIXEL_RGBA8_EQ(expectedU2, mFB.color, 2, 0); EXPECT_PIXEL_RGBA8_EQ(expectedU2, mRenderPass.color, 2, 0);
EXPECT_PIXEL_RGBA8_EQ(expectedU3, mFB.color, 3, 0); EXPECT_PIXEL_RGBA8_EQ(expectedU3, mRenderPass.color, 3, 0);
EXPECT_PIXEL_RGBA8_EQ(expectedV2, mFB.color, 0, 2); EXPECT_PIXEL_RGBA8_EQ(expectedV2, mRenderPass.color, 0, 2);
EXPECT_PIXEL_RGBA8_EQ(expectedV3, mFB.color, 0, 3); EXPECT_PIXEL_RGBA8_EQ(expectedV3, mRenderPass.color, 0, 3);
// TODO: add tests for W address mode, once NXT supports 3D textures // TODO: add tests for W address mode, once NXT supports 3D textures
} }
utils::BasicFramebuffer mFB; utils::BasicRenderPass mRenderPass;
nxt::BindGroupLayout mBindGroupLayout; nxt::BindGroupLayout mBindGroupLayout;
nxt::RenderPipeline mPipeline; nxt::RenderPipeline mPipeline;
nxt::TextureView mTextureView; nxt::TextureView mTextureView;

View File

@ -18,7 +18,7 @@
class ScissorTest: public NXTTest { class ScissorTest: public NXTTest {
protected: protected:
nxt::RenderPipeline CreateQuadPipeline(const nxt::RenderPass& renderPass) { nxt::RenderPipeline CreateQuadPipeline(nxt::TextureFormat format) {
nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"( nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
#version 450 #version 450
const vec2 pos[6] = vec2[6]( const vec2 pos[6] = vec2[6](
@ -37,7 +37,7 @@ class ScissorTest: public NXTTest {
})"); })");
nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder() nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(renderPass, 0) .SetColorAttachmentFormat(0, format)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.GetResult(); .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 that by default the scissor test is disabled and the whole attachment can be drawn to.
TEST_P(ScissorTest, DefaultsToWholeRenderTarget) { TEST_P(ScissorTest, DefaultsToWholeRenderTarget) {
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 100, 100); utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 100, 100);
nxt::RenderPipeline pipeline = CreateQuadPipeline(fb.renderPass); nxt::RenderPipeline pipeline = CreateQuadPipeline(renderPass.colorFormat);
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.DrawArrays(6, 1, 0, 0) .DrawArrays(6, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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), renderPass.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), renderPass.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), renderPass.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, 99, 99);
} }
// Test setting the scissor to something larger than the attachments. // Test setting the scissor to something larger than the attachments.
TEST_P(ScissorTest, LargerThanAttachment) { TEST_P(ScissorTest, LargerThanAttachment) {
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 100, 100); utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 100, 100);
nxt::RenderPipeline pipeline = CreateQuadPipeline(fb.renderPass); nxt::RenderPipeline pipeline = CreateQuadPipeline(renderPass.colorFormat);
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetScissorRect(0, 0, 200, 200) .SetScissorRect(0, 0, 200, 200)
.DrawArrays(6, 1, 0, 0) .DrawArrays(6, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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), renderPass.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), renderPass.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), renderPass.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, 99, 99);
} }
// Test setting an empty scissor rect // Test setting an empty scissor rect
@ -98,86 +94,76 @@ TEST_P(ScissorTest, EmptyRect) {
return; return;
} }
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 2, 2); utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 2, 2);
nxt::RenderPipeline pipeline = CreateQuadPipeline(fb.renderPass); nxt::RenderPipeline pipeline = CreateQuadPipeline(renderPass.colorFormat);
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetScissorRect(0, 0, 0, 0) .SetScissorRect(0, 0, 0, 0)
.DrawArrays(6, 1, 0, 0) .DrawArrays(6, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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), renderPass.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), renderPass.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), renderPass.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, 1, 1);
} }
// Test setting a partial scissor (not empty, not full attachment) // Test setting a partial scissor (not empty, not full attachment)
TEST_P(ScissorTest, PartialRect) { TEST_P(ScissorTest, PartialRect) {
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 100, 100); utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 100, 100);
nxt::RenderPipeline pipeline = CreateQuadPipeline(fb.renderPass); nxt::RenderPipeline pipeline = CreateQuadPipeline(renderPass.colorFormat);
constexpr uint32_t kX = 3; constexpr uint32_t kX = 3;
constexpr uint32_t kY = 7; constexpr uint32_t kY = 7;
constexpr uint32_t kW = 5; constexpr uint32_t kW = 5;
constexpr uint32_t kH = 13; constexpr uint32_t kH = 13;
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.SetScissorRect(kX, kY, kW, kH) .SetScissorRect(kX, kY, kW, kH)
.DrawArrays(6, 1, 0, 0) .DrawArrays(6, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); queue.Submit(1, &commands);
// Test the two opposite corners of the scissor box. With one pixel inside and on outside // 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, 0, 0, 0), renderPass.color, kX - 1, kY - 1);
EXPECT_PIXEL_RGBA8_EQ(RGBA8(0, 255, 0, 255), fb.color, kX, kY); 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, 0, 0, 0), renderPass.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, 255, 0, 255), renderPass.color, kX + kW - 1, kY + kH - 1);
} }
// Test that the scissor setting doesn't get inherited between renderpasses // Test that the scissor setting doesn't get inherited between renderpasses
// TODO(cwallez@chromium.org): do the same between subpasses?
TEST_P(ScissorTest, NoInheritanceBetweenRenderPass) { TEST_P(ScissorTest, NoInheritanceBetweenRenderPass) {
utils::BasicFramebuffer fb = utils::CreateBasicFramebuffer(device, 100, 100); utils::BasicRenderPass renderPass = utils::CreateBasicRenderPass(device, 100, 100);
nxt::RenderPipeline pipeline = CreateQuadPipeline(fb.renderPass); nxt::RenderPipeline pipeline = CreateQuadPipeline(renderPass.colorFormat);
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
// RenderPass 1 set the scissor // RenderPass 1 set the scissor
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetScissorRect(0, 0, 0, 0) .SetScissorRect(0, 0, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
// RenderPass 2 draw a full quad, it shouldn't be scissored // RenderPass 2 draw a full quad, it shouldn't be scissored
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.DrawArrays(6, 1, 0, 0) .DrawArrays(6, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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), renderPass.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), renderPass.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), renderPass.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, 99, 99);
} }
NXT_INSTANTIATE_TEST(ScissorTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend) NXT_INSTANTIATE_TEST(ScissorTest, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)

View File

@ -20,7 +20,7 @@ class ViewportOrientationTests : public NXTTest {};
// Test that the pixel in viewport coordinate (-1, -1) matches texel (0, 0) // Test that the pixel in viewport coordinate (-1, -1) matches texel (0, 0)
TEST_P(ViewportOrientationTests, OriginAt0x0) { 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"( nxt::ShaderModule vsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Vertex, R"(
#version 450 #version 450
@ -36,27 +36,25 @@ TEST_P(ViewportOrientationTests, OriginAt0x0) {
})"); })");
nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder() nxt::RenderPipeline pipeline = device.CreateRenderPipelineBuilder()
.SetSubpass(fb.renderPass, 0) .SetColorAttachmentFormat(0, renderPass.colorFormat)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetPrimitiveTopology(nxt::PrimitiveTopology::PointList) .SetPrimitiveTopology(nxt::PrimitiveTopology::PointList)
.GetResult(); .GetResult();
nxt::CommandBuffer commands = device.CreateCommandBufferBuilder() nxt::CommandBuffer commands = device.CreateCommandBufferBuilder()
.BeginRenderPass(fb.renderPass, fb.framebuffer) .BeginRenderPass(renderPass.renderPassInfo)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline) .SetRenderPipeline(pipeline)
.DrawArrays(1, 1, 0, 0) .DrawArrays(1, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
queue.Submit(1, &commands); 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), renderPass.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), renderPass.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), renderPass.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, 1, 1);
} }
NXT_INSTANTIATE_TEST(ViewportOrientationTests, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend) NXT_INSTANTIATE_TEST(ViewportOrientationTests, D3D12Backend, MetalBackend, OpenGLBackend, VulkanBackend)

View File

@ -23,43 +23,15 @@ TEST_F(CommandBufferValidationTest, Empty) {
.GetResult(); .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 // Tests for basic render pass usage
TEST_F(CommandBufferValidationTest, RenderPass) { TEST_F(CommandBufferValidationTest, RenderPass) {
auto renderpass = AssertWillBeSuccess(device.CreateRenderPassBuilder()) auto renderpass = CreateSimpleRenderPass();
.SetAttachmentCount(0)
.SetSubpassCount(1)
.GetResult();
auto framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder())
.SetRenderPass(renderpass)
.SetDimensions(100, 100)
.GetResult();
AssertWillBeSuccess(device.CreateCommandBufferBuilder()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderpass)
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder()) AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderpass)
.GetResult(); .GetResult();
} }

View File

@ -17,23 +17,13 @@
class SetScissorRectTest : public ValidationTest { class SetScissorRectTest : public ValidationTest {
}; };
// Test to check that SetScissor can only be used inside render subpasses // Test to check that SetScissor can only be used inside render passes
TEST_F(SetScissorRectTest, AllowedOnlyInRenderSubpass) { TEST_F(SetScissorRectTest, AllowedOnlyInRenderPass) {
DummyRenderPass renderPass = CreateDummyRenderPass(); DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer) .BeginRenderPass(renderPass.renderPass)
.BeginRenderSubpass()
.SetScissorRect(0, 0, 1, 1) .SetScissorRect(0, 0, 1, 1)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.SetScissorRect(0, 0, 1, 1)
.BeginRenderSubpass()
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
@ -53,10 +43,8 @@ TEST_F(SetScissorRectTest, EmptyScissor) {
DummyRenderPass renderPass = CreateDummyRenderPass(); DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer) .BeginRenderPass(renderPass.renderPass)
.BeginRenderSubpass()
.SetScissorRect(0, 0, 0, 0) .SetScissorRect(0, 0, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
} }
@ -68,10 +56,8 @@ TEST_F(SetScissorRectTest, ScissorLargerThanFramebuffer) {
DummyRenderPass renderPass = CreateDummyRenderPass(); DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer) .BeginRenderPass(renderPass.renderPass)
.BeginRenderSubpass()
.SetScissorRect(0, 0, renderPass.width + 1, renderPass.height + 1) .SetScissorRect(0, 0, renderPass.width + 1, renderPass.height + 1)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
} }
@ -79,23 +65,13 @@ TEST_F(SetScissorRectTest, ScissorLargerThanFramebuffer) {
class SetBlendColorTest : public ValidationTest { class SetBlendColorTest : public ValidationTest {
}; };
// Test to check that SetBlendColor can only be used inside render subpasses // Test to check that SetBlendColor can only be used inside render passes
TEST_F(SetBlendColorTest, AllowedOnlyInRenderSubpass) { TEST_F(SetBlendColorTest, AllowedOnlyInRenderPass) {
DummyRenderPass renderPass = CreateDummyRenderPass(); DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer) .BeginRenderPass(renderPass.renderPass)
.BeginRenderSubpass()
.SetBlendColor(0.0f, 0.0f, 0.0f, 0.0f) .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() .EndRenderPass()
.GetResult(); .GetResult();
@ -115,10 +91,8 @@ TEST_F(SetBlendColorTest, AnyValueAllowed) {
DummyRenderPass renderPass = CreateDummyRenderPass(); DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer) .BeginRenderPass(renderPass.renderPass)
.BeginRenderSubpass()
.SetBlendColor(-1.0f, 42.0f, -0.0f, 0.0f) .SetBlendColor(-1.0f, 42.0f, -0.0f, 0.0f)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
} }
@ -126,23 +100,13 @@ TEST_F(SetBlendColorTest, AnyValueAllowed) {
class SetStencilReferenceTest : public ValidationTest { class SetStencilReferenceTest : public ValidationTest {
}; };
// Test to check that SetStencilReference can only be used inside render subpasses // Test to check that SetStencilReference can only be used inside render passes
TEST_F(SetStencilReferenceTest, AllowedOnlyInRenderSubpass) { TEST_F(SetStencilReferenceTest, AllowedOnlyInRenderPass) {
DummyRenderPass renderPass = CreateDummyRenderPass(); DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer) .BeginRenderPass(renderPass.renderPass)
.BeginRenderSubpass()
.SetStencilReference(0) .SetStencilReference(0)
.EndRenderSubpass()
.EndRenderPass()
.GetResult();
AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer)
.SetStencilReference(0)
.BeginRenderSubpass()
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
@ -162,10 +126,8 @@ TEST_F(SetStencilReferenceTest, AllBitsAllowed) {
DummyRenderPass renderPass = CreateDummyRenderPass(); DummyRenderPass renderPass = CreateDummyRenderPass();
AssertWillBeSuccess(device.CreateCommandBufferBuilder()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderPass.renderPass, renderPass.framebuffer) .BeginRenderPass(renderPass.renderPass)
.BeginRenderSubpass()
.SetStencilReference(0xFFFFFFFF) .SetStencilReference(0xFFFFFFFF)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
} }

View File

@ -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.
}

View File

@ -46,7 +46,7 @@ class InputStateTest : public ValidationTest {
builder = AssertWillBeError(device.CreateRenderPipelineBuilder()); 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::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetInputState(inputState) .SetInputState(inputState)

View File

@ -54,11 +54,9 @@ TEST_F(PushConstantTest, Success) {
.SetPushConstants(nxt::ShaderStageBit::Compute, 0, 1, constants) .SetPushConstants(nxt::ShaderStageBit::Compute, 0, 1, constants)
.EndComputePass() .EndComputePass()
// PushConstants in a render subpass // PushConstants in a render pass
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer) .BeginRenderPass(renderpassData.renderPass)
.BeginRenderSubpass()
.SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, constants) .SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, constants)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
// Setting all constants // Setting all constants
@ -120,36 +118,9 @@ TEST_F(PushConstantTest, NotInPass) {
.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, constants) .SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 1, constants)
.GetResult(); .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) { TEST_F(PushConstantTest, StageForComputePass) {
// Control case: setting to the compute stage in compute passes // 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 valid stages for render passes
TEST_F(PushConstantTest, StageForSubpass) { TEST_F(PushConstantTest, StageForRenderPass) {
DummyRenderPass renderpassData = CreateDummyRenderPass(); 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()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer) .BeginRenderPass(renderpassData.renderPass)
.BeginRenderSubpass()
.SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, constants) .SetPushConstants(nxt::ShaderStageBit::Vertex | nxt::ShaderStageBit::Fragment, 0, 1, constants)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
} }
@ -197,10 +166,8 @@ TEST_F(PushConstantTest, StageForSubpass) {
// Compute stage is disallowed // Compute stage is disallowed
{ {
AssertWillBeError(device.CreateCommandBufferBuilder()) AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer) .BeginRenderPass(renderpassData.renderPass)
.BeginRenderSubpass()
.SetPushConstants(nxt::ShaderStageBit::Compute, 0, 1, constants) .SetPushConstants(nxt::ShaderStageBit::Compute, 0, 1, constants)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
} }
@ -208,10 +175,8 @@ TEST_F(PushConstantTest, StageForSubpass) {
// A None shader stage mask is valid. // A None shader stage mask is valid.
{ {
AssertWillBeSuccess(device.CreateCommandBufferBuilder()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpassData.renderPass, renderpassData.framebuffer) .BeginRenderPass(renderpassData.renderPass)
.BeginRenderSubpass()
.SetPushConstants(nxt::ShaderStageBit::None, 0, 1, constants) .SetPushConstants(nxt::ShaderStageBit::None, 0, 1, constants)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
} }

View File

@ -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

View File

@ -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();
}

View File

@ -14,6 +14,7 @@
#include "tests/unittests/validation/ValidationTest.h" #include "tests/unittests/validation/ValidationTest.h"
#include "common/Constants.h"
#include "utils/NXTHelpers.h" #include "utils/NXTHelpers.h"
class RenderPipelineValidationTest : public ValidationTest { class RenderPipelineValidationTest : public ValidationTest {
@ -21,7 +22,7 @@ class RenderPipelineValidationTest : public ValidationTest {
void SetUp() override { void SetUp() override {
ValidationTest::SetUp(); ValidationTest::SetUp();
CreateSimpleRenderPassAndFramebuffer(device, &renderpass, &framebuffer); renderpass = CreateSimpleRenderPass();
pipelineLayout = device.CreatePipelineLayoutBuilder().GetResult(); pipelineLayout = device.CreatePipelineLayoutBuilder().GetResult();
@ -45,7 +46,7 @@ class RenderPipelineValidationTest : public ValidationTest {
} }
nxt::RenderPipelineBuilder& AddDefaultStates(nxt::RenderPipelineBuilder&& builder) { nxt::RenderPipelineBuilder& AddDefaultStates(nxt::RenderPipelineBuilder&& builder) {
builder.SetSubpass(renderpass, 0) builder.SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -53,8 +54,7 @@ class RenderPipelineValidationTest : public ValidationTest {
return builder; return builder;
} }
nxt::RenderPass renderpass; nxt::RenderPassInfo renderpass;
nxt::Framebuffer framebuffer;
nxt::ShaderModule vsModule; nxt::ShaderModule vsModule;
nxt::ShaderModule fsModule; nxt::ShaderModule fsModule;
nxt::InputState inputState; nxt::InputState inputState;
@ -81,7 +81,7 @@ TEST_F(RenderPipelineValidationTest, CreationMissingProperty) {
// Vertex stage not set // Vertex stage not set
{ {
AssertWillBeError(device.CreateRenderPipelineBuilder()) AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList) .SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList)
@ -91,14 +91,14 @@ TEST_F(RenderPipelineValidationTest, CreationMissingProperty) {
// Fragment stage not set // Fragment stage not set
{ {
AssertWillBeError(device.CreateRenderPipelineBuilder()) AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList) .SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList)
.GetResult(); .GetResult();
} }
// Subpass not set // No attachment set
{ {
AssertWillBeError(device.CreateRenderPipelineBuilder()) AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
@ -112,47 +112,9 @@ TEST_F(RenderPipelineValidationTest, CreationMissingProperty) {
TEST_F(RenderPipelineValidationTest, BlendState) { TEST_F(RenderPipelineValidationTest, BlendState) {
// Fails because blend state is set on a nonexistent color attachment // Fails because blend state is set on a nonexistent color attachment
{ {
auto texture1 = device.CreateTextureBuilder() // This one succeeds because attachment 0 is the color attachment
.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
AssertWillBeSuccess(device.CreateRenderPipelineBuilder()) AssertWillBeSuccess(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -160,9 +122,9 @@ TEST_F(RenderPipelineValidationTest, BlendState) {
.SetColorAttachmentBlendState(0, blendState) .SetColorAttachmentBlendState(0, blendState)
.GetResult(); .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()) AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -174,7 +136,7 @@ TEST_F(RenderPipelineValidationTest, BlendState) {
// Fails because color attachment is out of bounds // Fails because color attachment is out of bounds
{ {
AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder())) AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder()))
.SetColorAttachmentBlendState(1, blendState) .SetColorAttachmentBlendState(kMaxColorAttachments, blendState)
.GetResult(); .GetResult();
} }
@ -192,7 +154,7 @@ TEST_F(RenderPipelineValidationTest, DISABLED_TodoCreationMissingProperty) {
// Fails because pipeline layout is not set // Fails because pipeline layout is not set
{ {
AssertWillBeError(device.CreateRenderPipelineBuilder()) AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList) .SetPrimitiveTopology(nxt::PrimitiveTopology::TriangleList)
@ -202,7 +164,7 @@ TEST_F(RenderPipelineValidationTest, DISABLED_TodoCreationMissingProperty) {
// Fails because primitive topology is not set // Fails because primitive topology is not set
{ {
AssertWillBeError(device.CreateRenderPipelineBuilder()) AssertWillBeError(device.CreateRenderPipelineBuilder())
.SetSubpass(renderpass, 0) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetLayout(pipelineLayout) .SetLayout(pipelineLayout)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
@ -240,13 +202,6 @@ TEST_F(RenderPipelineValidationTest, DISABLED_CreationDuplicates) {
.GetResult(); .GetResult();
} }
// Fails because subpass is set twice
{
AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder()))
.SetSubpass(renderpass, 0)
.GetResult();
}
// Fails because the layout is set twice // Fails because the layout is set twice
{ {
AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder())) AddDefaultStates(AssertWillBeError(device.CreateRenderPipelineBuilder()))

View File

@ -69,7 +69,7 @@ bool ValidationTest::EndExpectDeviceError() {
return mError; return mError;
} }
void ValidationTest::CreateSimpleRenderPassAndFramebuffer(const nxt::Device& device, nxt::RenderPass* renderpass, nxt::Framebuffer* framebuffer) { nxt::RenderPassInfo ValidationTest::CreateSimpleRenderPass() {
auto colorBuffer = device.CreateTextureBuilder() auto colorBuffer = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D) .SetDimension(nxt::TextureDimension::e2D)
.SetExtent(640, 480, 1) .SetExtent(640, 480, 1)
@ -81,17 +81,8 @@ void ValidationTest::CreateSimpleRenderPassAndFramebuffer(const nxt::Device& dev
auto colorView = colorBuffer.CreateTextureViewBuilder() auto colorView = colorBuffer.CreateTextureViewBuilder()
.GetResult(); .GetResult();
*renderpass = device.CreateRenderPassBuilder() return device.CreateRenderPassInfoBuilder()
.SetAttachmentCount(1) .SetColorAttachment(0, colorView, nxt::LoadOp::Clear)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
*framebuffer = device.CreateFramebufferBuilder()
.SetRenderPass(*renderpass)
.SetDimensions(640, 480)
.SetAttachment(0, colorView)
.GetResult(); .GetResult();
} }
@ -128,13 +119,6 @@ ValidationTest::DummyRenderPass ValidationTest::CreateDummyRenderPass() {
dummy.height = 400; dummy.height = 400;
dummy.attachmentFormat = nxt::TextureFormat::R8G8B8A8Unorm; 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()) dummy.attachment = AssertWillBeSuccess(device.CreateTextureBuilder())
.SetDimension(nxt::TextureDimension::e2D) .SetDimension(nxt::TextureDimension::e2D)
.SetExtent(dummy.width, dummy.height, 1) .SetExtent(dummy.width, dummy.height, 1)
@ -146,10 +130,8 @@ ValidationTest::DummyRenderPass ValidationTest::CreateDummyRenderPass() {
nxt::TextureView view = AssertWillBeSuccess(dummy.attachment.CreateTextureViewBuilder()).GetResult(); nxt::TextureView view = AssertWillBeSuccess(dummy.attachment.CreateTextureViewBuilder()).GetResult();
dummy.framebuffer = AssertWillBeSuccess(device.CreateFramebufferBuilder()) dummy.renderPass = AssertWillBeSuccess(device.CreateRenderPassInfoBuilder())
.SetRenderPass(dummy.renderPass) .SetColorAttachment(0, view, nxt::LoadOp::Clear)
.SetAttachment(0, view)
.SetDimensions(dummy.width, dummy.height)
.GetResult(); .GetResult();
return dummy; return dummy;

View File

@ -48,13 +48,12 @@ class ValidationTest : public testing::Test {
void StartExpectDeviceError(); void StartExpectDeviceError();
bool EndExpectDeviceError(); 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. // Helper functions to create objects to test validation.
struct DummyRenderPass { struct DummyRenderPass {
nxt::RenderPass renderPass; nxt::RenderPassInfo renderPass;
nxt::Framebuffer framebuffer;
nxt::Texture attachment; nxt::Texture attachment;
nxt::TextureFormat attachmentFormat; nxt::TextureFormat attachmentFormat;
uint32_t width; uint32_t width;

View File

@ -23,6 +23,8 @@ class VertexBufferValidationTest : public ValidationTest {
void SetUp() override { void SetUp() override {
ValidationTest::SetUp(); ValidationTest::SetUp();
renderpass = CreateSimpleRenderPass();
fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"( fsModule = utils::CreateShaderModule(device, nxt::ShaderStage::Fragment, R"(
#version 450 #version 450
layout(location = 0) out vec4 fragColor; 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> template <unsigned int N>
std::array<nxt::Buffer, N> MakeVertexBuffers() { std::array<nxt::Buffer, N> MakeVertexBuffers() {
std::array<nxt::Buffer, N> buffers; std::array<nxt::Buffer, N> buffers;
@ -105,102 +77,89 @@ class VertexBufferValidationTest : public ValidationTest {
return builder.GetResult(); 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() return device.CreateRenderPipelineBuilder()
.SetSubpass(renderpass, subpass) .SetColorAttachmentFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.SetStage(nxt::ShaderStage::Vertex, vsModule, "main") .SetStage(nxt::ShaderStage::Vertex, vsModule, "main")
.SetStage(nxt::ShaderStage::Fragment, fsModule, "main") .SetStage(nxt::ShaderStage::Fragment, fsModule, "main")
.SetInputState(inputState) .SetInputState(inputState)
.GetResult(); .GetResult();
} }
nxt::RenderPass renderpass; nxt::RenderPassInfo renderpass;
nxt::Framebuffer framebuffer;
nxt::ShaderModule fsModule; nxt::ShaderModule fsModule;
}; };
TEST_F(VertexBufferValidationTest, VertexInputsInheritedBetweenPipelines) { TEST_F(VertexBufferValidationTest, VertexInputsInheritedBetweenPipelines) {
MakeRenderPassAndFrameBuffer(1);
auto vsModule2 = MakeVertexShader(2); auto vsModule2 = MakeVertexShader(2);
auto vsModule1 = MakeVertexShader(1); auto vsModule1 = MakeVertexShader(1);
auto inputState2 = MakeInputState(2); auto inputState2 = MakeInputState(2);
auto inputState1 = MakeInputState(1); auto inputState1 = MakeInputState(1);
auto pipeline2 = MakeRenderPipeline(0, vsModule2, inputState2); auto pipeline2 = MakeRenderPipeline(vsModule2, inputState2);
auto pipeline1 = MakeRenderPipeline(0, vsModule1, inputState1); auto pipeline1 = MakeRenderPipeline(vsModule1, inputState1);
auto vertexBuffers = MakeVertexBuffers<2>(); auto vertexBuffers = MakeVertexBuffers<2>();
uint32_t offsets[] = { 0, 0 }; uint32_t offsets[] = { 0, 0 };
// Check failure when vertex buffer is not set // Check failure when vertex buffer is not set
AssertWillBeError(device.CreateCommandBufferBuilder()) AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderpass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline1) .SetRenderPipeline(pipeline1)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
// Check success when vertex buffer is inherited from previous pipeline // Check success when vertex buffer is inherited from previous pipeline
AssertWillBeSuccess(device.CreateCommandBufferBuilder()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderpass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline2) .SetRenderPipeline(pipeline2)
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets) .SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.SetRenderPipeline(pipeline1) .SetRenderPipeline(pipeline1)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
} }
TEST_F(VertexBufferValidationTest, VertexInputsNotInheritedBetweenSubpasses) { TEST_F(VertexBufferValidationTest, VertexInputsNotInheritedBetweenRendePasses) {
MakeRenderPassAndFrameBuffer(2);
auto vsModule2 = MakeVertexShader(2); auto vsModule2 = MakeVertexShader(2);
auto vsModule1 = MakeVertexShader(1); auto vsModule1 = MakeVertexShader(1);
auto inputState2 = MakeInputState(2); auto inputState2 = MakeInputState(2);
auto inputState1 = MakeInputState(1); auto inputState1 = MakeInputState(1);
auto pipeline2 = MakeRenderPipeline(0, vsModule2, inputState2); auto pipeline2 = MakeRenderPipeline(vsModule2, inputState2);
auto pipeline1 = MakeRenderPipeline(1, vsModule1, inputState1); auto pipeline1 = MakeRenderPipeline(vsModule1, inputState1);
auto vertexBuffers = MakeVertexBuffers<2>(); auto vertexBuffers = MakeVertexBuffers<2>();
uint32_t offsets[] = { 0, 0 }; 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()) AssertWillBeSuccess(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderpass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline2) .SetRenderPipeline(pipeline2)
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets) .SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass() .EndRenderPass()
.BeginRenderSubpass() .BeginRenderPass(renderpass)
.SetRenderPipeline(pipeline1) .SetRenderPipeline(pipeline1)
.SetVertexBuffers(0, 1, vertexBuffers.data(), offsets) .SetVertexBuffers(0, 1, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
// Check failure because vertex buffer is not inherited in second subpass // Check failure because vertex buffer is not inherited in second subpass
AssertWillBeError(device.CreateCommandBufferBuilder()) AssertWillBeError(device.CreateCommandBufferBuilder())
.BeginRenderPass(renderpass, framebuffer) .BeginRenderPass(renderpass)
.BeginRenderSubpass()
.SetRenderPipeline(pipeline2) .SetRenderPipeline(pipeline2)
.SetVertexBuffers(0, 2, vertexBuffers.data(), offsets) .SetVertexBuffers(0, 2, vertexBuffers.data(), offsets)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass() .EndRenderPass()
.BeginRenderSubpass() .BeginRenderPass(renderpass)
.SetRenderPipeline(pipeline1) .SetRenderPipeline(pipeline1)
.DrawArrays(3, 1, 0, 0) .DrawArrays(3, 1, 0, 0)
.EndRenderSubpass()
.EndRenderPass() .EndRenderPass()
.GetResult(); .GetResult();
} }

View File

@ -111,25 +111,18 @@ namespace utils {
return buffer; return buffer;
} }
BasicFramebuffer CreateBasicFramebuffer(const nxt::Device& device, BasicRenderPass CreateBasicRenderPass(const nxt::Device& device,
uint32_t width, uint32_t width,
uint32_t height) { uint32_t height) {
BasicFramebuffer result; BasicRenderPass result;
result.width = width; result.width = width;
result.height = height; result.height = height;
result.renderPass = device.CreateRenderPassBuilder() result.colorFormat = nxt::TextureFormat::R8G8B8A8Unorm;
.SetAttachmentCount(1)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.GetResult();
result.color = device.CreateTextureBuilder() result.color = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D) .SetDimension(nxt::TextureDimension::e2D)
.SetExtent(width, height, 1) .SetExtent(width, height, 1)
.SetFormat(nxt::TextureFormat::R8G8B8A8Unorm) .SetFormat(result.colorFormat)
.SetMipLevels(1) .SetMipLevels(1)
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment | .SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment |
nxt::TextureUsageBit::TransferSrc) nxt::TextureUsageBit::TransferSrc)
@ -137,11 +130,8 @@ namespace utils {
.GetResult(); .GetResult();
nxt::TextureView colorView = result.color.CreateTextureViewBuilder().GetResult(); nxt::TextureView colorView = result.color.CreateTextureViewBuilder().GetResult();
result.renderPassInfo = device.CreateRenderPassInfoBuilder()
result.framebuffer = device.CreateFramebufferBuilder() .SetColorAttachment(0, colorView, nxt::LoadOp::Clear)
.SetRenderPass(result.renderPass)
.SetAttachment(0, colorView)
.SetDimensions(width, height)
.GetResult(); .GetResult();
return result; return result;

View File

@ -37,14 +37,14 @@ namespace utils {
usage); usage);
} }
struct BasicFramebuffer { struct BasicRenderPass {
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
nxt::RenderPass renderPass;
nxt::Texture color; nxt::Texture color;
nxt::Framebuffer framebuffer; nxt::TextureFormat colorFormat;
nxt::RenderPassInfo renderPassInfo;
}; };
BasicFramebuffer CreateBasicFramebuffer(const nxt::Device& device, BasicRenderPass CreateBasicRenderPass(const nxt::Device& device,
uint32_t width, uint32_t width,
uint32_t height); uint32_t height);