Load operations (#105)
* load ops: design + implementation (all backends) * Animometer/glTFViewer: use just one subpass per frame
This commit is contained in:
parent
3d1154786f
commit
b985431c82
|
@ -138,17 +138,15 @@ void frame() {
|
||||||
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
||||||
std::vector<nxt::CommandBuffer> commands(50);
|
nxt::CommandBuffer commands;
|
||||||
for (size_t j = 0; j < 50; j++) {
|
{
|
||||||
|
|
||||||
nxt::CommandBufferBuilder builder = device.CreateCommandBufferBuilder()
|
nxt::CommandBufferBuilder builder = device.CreateCommandBufferBuilder()
|
||||||
.BeginRenderPass(renderpass, framebuffer)
|
.BeginRenderPass(renderpass, framebuffer)
|
||||||
.BeginRenderSubpass()
|
.BeginRenderSubpass()
|
||||||
.SetRenderPipeline(pipeline)
|
.SetRenderPipeline(pipeline)
|
||||||
.Clone();
|
.Clone();
|
||||||
|
|
||||||
for (int k = 0; k < 200; k++) {
|
for (int k = 0; k < 10000; k++) {
|
||||||
|
|
||||||
shaderData[i].time = f / 60.0f;
|
shaderData[i].time = f / 60.0f;
|
||||||
builder.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 6, reinterpret_cast<uint32_t*>(&shaderData[i]))
|
builder.SetPushConstants(nxt::ShaderStageBit::Vertex, 0, 6, reinterpret_cast<uint32_t*>(&shaderData[i]))
|
||||||
.DrawArrays(3, 1, 0, 0);
|
.DrawArrays(3, 1, 0, 0);
|
||||||
|
@ -157,10 +155,10 @@ void frame() {
|
||||||
|
|
||||||
builder.EndRenderSubpass();
|
builder.EndRenderSubpass();
|
||||||
builder.EndRenderPass();
|
builder.EndRenderPass();
|
||||||
commands[j] = builder.GetResult();
|
commands = builder.GetResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.Submit(50, commands.data());
|
queue.Submit(1, &commands);
|
||||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
swapchain.Present(backbuffer);
|
swapchain.Present(backbuffer);
|
||||||
DoFlush();
|
DoFlush();
|
||||||
|
|
|
@ -126,7 +126,9 @@ nxt::RenderPass CreateDefaultRenderPass(const nxt::Device& device) {
|
||||||
return device.CreateRenderPassBuilder()
|
return device.CreateRenderPassBuilder()
|
||||||
.SetAttachmentCount(2)
|
.SetAttachmentCount(2)
|
||||||
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
|
||||||
|
.AttachmentSetColorLoadOp(0, nxt::LoadOp::Clear)
|
||||||
.AttachmentSetFormat(1, nxt::TextureFormat::D32FloatS8Uint)
|
.AttachmentSetFormat(1, nxt::TextureFormat::D32FloatS8Uint)
|
||||||
|
.AttachmentSetDepthStencilLoadOps(1, nxt::LoadOp::Clear, nxt::LoadOp::Clear)
|
||||||
.SetSubpassCount(1)
|
.SetSubpassCount(1)
|
||||||
.SubpassSetColorAttachment(0, 0, 0)
|
.SubpassSetColorAttachment(0, 0, 0)
|
||||||
.SubpassSetDepthStencilAttachment(0, 1)
|
.SubpassSetDepthStencilAttachment(0, 1)
|
||||||
|
|
|
@ -80,7 +80,6 @@ nxt::Queue queue;
|
||||||
nxt::SwapChain swapchain;
|
nxt::SwapChain swapchain;
|
||||||
nxt::TextureView depthStencilView;
|
nxt::TextureView depthStencilView;
|
||||||
nxt::RenderPass renderpass;
|
nxt::RenderPass renderpass;
|
||||||
nxt::Framebuffer lastFramebuffer;
|
|
||||||
|
|
||||||
nxt::Buffer defaultBuffer;
|
nxt::Buffer defaultBuffer;
|
||||||
std::map<std::string, nxt::Buffer> buffers;
|
std::map<std::string, nxt::Buffer> buffers;
|
||||||
|
@ -478,8 +477,7 @@ namespace {
|
||||||
|
|
||||||
// Drawing
|
// Drawing
|
||||||
namespace {
|
namespace {
|
||||||
void drawMesh(const tinygltf::Mesh& iMesh, const glm::mat4& model) {
|
void drawMesh(nxt::CommandBufferBuilder& cmd, const tinygltf::Mesh& iMesh, const glm::mat4& model) {
|
||||||
nxt::CommandBufferBuilder cmd = device.CreateCommandBufferBuilder();
|
|
||||||
for (const auto& iPrim : iMesh.primitives) {
|
for (const auto& iPrim : iMesh.primitives) {
|
||||||
if (iPrim.mode != gl::Triangles) {
|
if (iPrim.mode != gl::Triangles) {
|
||||||
fprintf(stderr, "unsupported primitive mode %d\n", iPrim.mode);
|
fprintf(stderr, "unsupported primitive mode %d\n", iPrim.mode);
|
||||||
|
@ -507,8 +505,6 @@ namespace {
|
||||||
material.uniformBuffer.SetSubData(0,
|
material.uniformBuffer.SetSubData(0,
|
||||||
sizeof(u_transform_block) / sizeof(uint32_t),
|
sizeof(u_transform_block) / sizeof(uint32_t),
|
||||||
reinterpret_cast<const uint32_t*>(&transforms));
|
reinterpret_cast<const uint32_t*>(&transforms));
|
||||||
cmd.BeginRenderPass(renderpass, lastFramebuffer);
|
|
||||||
cmd.BeginRenderSubpass();
|
|
||||||
cmd.SetRenderPipeline(material.pipeline);
|
cmd.SetRenderPipeline(material.pipeline);
|
||||||
cmd.TransitionBufferUsage(material.uniformBuffer, nxt::BufferUsageBit::Uniform);
|
cmd.TransitionBufferUsage(material.uniformBuffer, nxt::BufferUsageBit::Uniform);
|
||||||
cmd.SetBindGroup(0, material.bindGroup0);
|
cmd.SetBindGroup(0, material.bindGroup0);
|
||||||
|
@ -551,14 +547,10 @@ namespace {
|
||||||
// DrawArrays
|
// DrawArrays
|
||||||
cmd.DrawArrays(vertexCount, 1, 0, 0);
|
cmd.DrawArrays(vertexCount, 1, 0, 0);
|
||||||
}
|
}
|
||||||
cmd.EndRenderSubpass();
|
|
||||||
cmd.EndRenderPass();
|
|
||||||
}
|
}
|
||||||
auto commands = cmd.GetResult();
|
|
||||||
queue.Submit(1, &commands);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawNode(const tinygltf::Node& node, const glm::mat4& parent = glm::mat4()) {
|
void drawNode(nxt::CommandBufferBuilder& cmd, const tinygltf::Node& node, const glm::mat4& parent = glm::mat4()) {
|
||||||
glm::mat4 model;
|
glm::mat4 model;
|
||||||
if (node.matrix.size() == 16) {
|
if (node.matrix.size() == 16) {
|
||||||
model = glm::make_mat4(node.matrix.data());
|
model = glm::make_mat4(node.matrix.data());
|
||||||
|
@ -579,22 +571,33 @@ namespace {
|
||||||
model = parent * model;
|
model = parent * model;
|
||||||
|
|
||||||
for (const auto& meshID : node.meshes) {
|
for (const auto& meshID : node.meshes) {
|
||||||
drawMesh(scene.meshes[meshID], model);
|
drawMesh(cmd, scene.meshes[meshID], model);
|
||||||
}
|
}
|
||||||
for (const auto& child : node.children) {
|
for (const auto& child : node.children) {
|
||||||
drawNode(scene.nodes.at(child), model);
|
drawNode(cmd, scene.nodes.at(child), model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void frame() {
|
void frame() {
|
||||||
nxt::Texture backbuffer;
|
nxt::Texture backbuffer;
|
||||||
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &lastFramebuffer);
|
nxt::Framebuffer framebuffer;
|
||||||
|
GetNextFramebuffer(device, renderpass, swapchain, depthStencilView, &backbuffer, &framebuffer);
|
||||||
|
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()
|
||||||
|
.BeginRenderPass(renderpass, framebuffer)
|
||||||
|
.BeginRenderSubpass()
|
||||||
|
.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(node);
|
drawNode(cmd, node);
|
||||||
}
|
}
|
||||||
|
auto commands = cmd.EndRenderSubpass()
|
||||||
|
.EndRenderPass()
|
||||||
|
.GetResult();
|
||||||
|
queue.Submit(1, &commands);
|
||||||
|
|
||||||
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
backbuffer.TransitionUsage(nxt::TextureUsageBit::Present);
|
||||||
swapchain.Present(backbuffer);
|
swapchain.Present(backbuffer);
|
||||||
DoFlush();
|
DoFlush();
|
||||||
|
|
46
next.json
46
next.json
|
@ -697,7 +697,29 @@
|
||||||
"category": "native"
|
"category": "native"
|
||||||
},
|
},
|
||||||
"framebuffer": {
|
"framebuffer": {
|
||||||
"category": "object"
|
"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": {
|
"framebuffer builder": {
|
||||||
"category": "object",
|
"category": "object",
|
||||||
|
@ -771,6 +793,13 @@
|
||||||
{"value": 1, "name": "instance"}
|
{"value": 1, "name": "instance"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"load op": {
|
||||||
|
"category": "enum",
|
||||||
|
"values": [
|
||||||
|
{"value": 0, "name": "clear"},
|
||||||
|
{"value": 1, "name": "load"}
|
||||||
|
]
|
||||||
|
},
|
||||||
"pipeline layout": {
|
"pipeline layout": {
|
||||||
"category": "object"
|
"category": "object"
|
||||||
},
|
},
|
||||||
|
@ -846,6 +875,21 @@
|
||||||
{"name": "format", "type": "texture format"}
|
{"name": "format", "type": "texture format"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "attachment set color load op",
|
||||||
|
"args": [
|
||||||
|
{"name": "attachment slot", "type": "uint32_t"},
|
||||||
|
{"name": "op", "type": "load op"}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "attachment set depth stencil load ops",
|
||||||
|
"args": [
|
||||||
|
{"name": "attachment slot", "type": "uint32_t"},
|
||||||
|
{"name": "depth op", "type": "load op"},
|
||||||
|
{"name": "stencil op", "type": "load op"}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "set subpass count",
|
"name": "set subpass count",
|
||||||
"args": [
|
"args": [
|
||||||
|
|
|
@ -25,16 +25,32 @@ namespace backend {
|
||||||
// Framebuffer
|
// Framebuffer
|
||||||
|
|
||||||
FramebufferBase::FramebufferBase(FramebufferBuilder* builder)
|
FramebufferBase::FramebufferBase(FramebufferBuilder* builder)
|
||||||
: renderPass(std::move(builder->renderPass)), width(builder->width), height(builder->height), textureViews(std::move(builder->textureViews)) {
|
: device(builder->device), renderPass(std::move(builder->renderPass)),
|
||||||
|
width(builder->width), height(builder->height), textureViews(std::move(builder->textureViews)),
|
||||||
|
clearColors(textureViews.size()), clearDepthStencils(textureViews.size()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
DeviceBase* FramebufferBase::GetDevice() {
|
||||||
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderPassBase* FramebufferBase::GetRenderPass() {
|
RenderPassBase* FramebufferBase::GetRenderPass() {
|
||||||
return renderPass.Get();
|
return renderPass.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureViewBase* FramebufferBase::GetTextureView(uint32_t index) {
|
TextureViewBase* FramebufferBase::GetTextureView(uint32_t attachmentSlot) {
|
||||||
ASSERT(index < textureViews.size());
|
ASSERT(attachmentSlot < textureViews.size());
|
||||||
return textureViews[index].Get();
|
return textureViews[attachmentSlot].Get();
|
||||||
|
}
|
||||||
|
|
||||||
|
FramebufferBase::ClearColor FramebufferBase::GetClearColor(uint32_t attachmentSlot) {
|
||||||
|
ASSERT(attachmentSlot < clearColors.size());
|
||||||
|
return clearColors[attachmentSlot];
|
||||||
|
}
|
||||||
|
|
||||||
|
FramebufferBase::ClearDepthStencil FramebufferBase::GetClearDepthStencil(uint32_t attachmentSlot) {
|
||||||
|
ASSERT(attachmentSlot < clearDepthStencils.size());
|
||||||
|
return clearDepthStencils[attachmentSlot];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t FramebufferBase::GetWidth() const {
|
uint32_t FramebufferBase::GetWidth() const {
|
||||||
|
@ -45,6 +61,30 @@ namespace backend {
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FramebufferBase::AttachmentSetClearColor(uint32_t attachmentSlot, float clearR, float clearG, float clearB, float clearA) {
|
||||||
|
if (attachmentSlot >= renderPass->GetAttachmentCount()) {
|
||||||
|
device->HandleError("Framebuffer attachment out of bounds");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ASSERT(attachmentSlot < clearColors.size());
|
||||||
|
auto& c = clearColors[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 >= renderPass->GetAttachmentCount()) {
|
||||||
|
device->HandleError("Framebuffer attachment out of bounds");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ASSERT(attachmentSlot < clearDepthStencils.size());
|
||||||
|
auto& c = clearDepthStencils[attachmentSlot];
|
||||||
|
c.depth = clearDepth;
|
||||||
|
c.stencil = clearStencil;
|
||||||
|
}
|
||||||
|
|
||||||
// FramebufferBuilder
|
// FramebufferBuilder
|
||||||
|
|
||||||
enum FramebufferSetProperties {
|
enum FramebufferSetProperties {
|
||||||
|
|
|
@ -28,18 +28,37 @@ namespace backend {
|
||||||
|
|
||||||
class FramebufferBase : public RefCounted {
|
class FramebufferBase : public RefCounted {
|
||||||
public:
|
public:
|
||||||
|
struct ClearColor {
|
||||||
|
float color[4] = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ClearDepthStencil {
|
||||||
|
float depth = 1.0f;
|
||||||
|
uint32_t stencil = 0;
|
||||||
|
};
|
||||||
|
|
||||||
FramebufferBase(FramebufferBuilder* builder);
|
FramebufferBase(FramebufferBuilder* builder);
|
||||||
|
|
||||||
|
DeviceBase* GetDevice();
|
||||||
RenderPassBase* GetRenderPass();
|
RenderPassBase* GetRenderPass();
|
||||||
TextureViewBase* GetTextureView(uint32_t index);
|
TextureViewBase* GetTextureView(uint32_t attachmentSlot);
|
||||||
|
ClearColor GetClearColor(uint32_t attachmentSlot);
|
||||||
|
ClearDepthStencil GetClearDepthStencil(uint32_t attachmentSlot);
|
||||||
uint32_t GetWidth() const;
|
uint32_t GetWidth() const;
|
||||||
uint32_t GetHeight() 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:
|
private:
|
||||||
|
DeviceBase* device;
|
||||||
Ref<RenderPassBase> renderPass;
|
Ref<RenderPassBase> renderPass;
|
||||||
uint32_t width = 0;
|
uint32_t width = 0;
|
||||||
uint32_t height = 0;
|
uint32_t height = 0;
|
||||||
std::vector<Ref<TextureViewBase>> textureViews;
|
std::vector<Ref<TextureViewBase>> textureViews;
|
||||||
|
std::vector<ClearColor> clearColors;
|
||||||
|
std::vector<ClearDepthStencil> clearDepthStencils;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FramebufferBuilder : public Builder<FramebufferBase> {
|
class FramebufferBuilder : public Builder<FramebufferBase> {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "backend/Device.h"
|
#include "backend/Device.h"
|
||||||
#include "backend/Texture.h"
|
#include "backend/Texture.h"
|
||||||
#include "common/Assert.h"
|
#include "common/Assert.h"
|
||||||
|
#include "common/BitSetIterator.h"
|
||||||
|
|
||||||
namespace backend {
|
namespace backend {
|
||||||
|
|
||||||
|
@ -25,6 +26,23 @@ namespace backend {
|
||||||
|
|
||||||
RenderPassBase::RenderPassBase(RenderPassBuilder* builder)
|
RenderPassBase::RenderPassBase(RenderPassBuilder* builder)
|
||||||
: attachments(std::move(builder->attachments)), subpasses(std::move(builder->subpasses)) {
|
: attachments(std::move(builder->attachments)), subpasses(std::move(builder->subpasses)) {
|
||||||
|
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 = attachments[attachmentSlot].firstSubpass;
|
||||||
|
if (firstSubpass == UINT32_MAX) {
|
||||||
|
firstSubpass = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (subpass.depthStencilAttachmentSet) {
|
||||||
|
auto attachmentSlot = subpass.depthStencilAttachment;
|
||||||
|
auto& firstSubpass = attachments[attachmentSlot].firstSubpass;
|
||||||
|
if (firstSubpass == UINT32_MAX) {
|
||||||
|
firstSubpass = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t RenderPassBase::GetAttachmentCount() const {
|
uint32_t RenderPassBase::GetAttachmentCount() const {
|
||||||
|
@ -95,8 +113,8 @@ namespace backend {
|
||||||
HandleError("Render pass attachment count not set yet");
|
HandleError("Render pass attachment count not set yet");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (attachmentSlot > attachments.size()) {
|
if (attachmentSlot >= attachments.size()) {
|
||||||
HandleError("Render pass attachment index out of bounds");
|
HandleError("Render pass attachment slot out of bounds");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (attachmentProperties[attachmentSlot][ATTACHMENT_PROPERTY_FORMAT]) {
|
if (attachmentProperties[attachmentSlot][ATTACHMENT_PROPERTY_FORMAT]) {
|
||||||
|
@ -108,6 +126,34 @@ namespace backend {
|
||||||
attachmentProperties[attachmentSlot].set(ATTACHMENT_PROPERTY_FORMAT);
|
attachmentProperties[attachmentSlot].set(ATTACHMENT_PROPERTY_FORMAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RenderPassBuilder::AttachmentSetColorLoadOp(uint32_t attachmentSlot, nxt::LoadOp op) {
|
||||||
|
if ((propertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
|
||||||
|
HandleError("Render pass attachment count not set yet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (attachmentSlot >= attachments.size()) {
|
||||||
|
HandleError("Render pass attachment slot out of bounds");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments[attachmentSlot].colorLoadOp = op;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderPassBuilder::AttachmentSetDepthStencilLoadOps(uint32_t attachmentSlot, nxt::LoadOp depthOp, nxt::LoadOp stencilOp) {
|
||||||
|
if ((propertiesSet & RENDERPASS_PROPERTY_ATTACHMENT_COUNT) == 0) {
|
||||||
|
HandleError("Render pass attachment count not set yet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (attachmentSlot >= attachments.size()) {
|
||||||
|
HandleError("Render pass attachment slot out of bounds");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachments[attachmentSlot].depthLoadOp = depthOp;
|
||||||
|
attachments[attachmentSlot].stencilLoadOp = stencilOp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RenderPassBuilder::SetSubpassCount(uint32_t subpassCount) {
|
void RenderPassBuilder::SetSubpassCount(uint32_t subpassCount) {
|
||||||
if ((propertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) != 0) {
|
if ((propertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) != 0) {
|
||||||
HandleError("Render pass subpass count property set multiple times");
|
HandleError("Render pass subpass count property set multiple times");
|
||||||
|
|
|
@ -34,10 +34,19 @@ namespace backend {
|
||||||
|
|
||||||
struct AttachmentInfo {
|
struct AttachmentInfo {
|
||||||
nxt::TextureFormat format;
|
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 {
|
struct SubpassInfo {
|
||||||
|
// Set of locations which are set
|
||||||
std::bitset<kMaxColorAttachments> colorAttachmentsSet;
|
std::bitset<kMaxColorAttachments> colorAttachmentsSet;
|
||||||
|
// Mapping from location to attachment slot
|
||||||
std::array<uint32_t, kMaxColorAttachments> colorAttachments;
|
std::array<uint32_t, kMaxColorAttachments> colorAttachments;
|
||||||
bool depthStencilAttachmentSet = false;
|
bool depthStencilAttachmentSet = false;
|
||||||
uint32_t depthStencilAttachment = 0;
|
uint32_t depthStencilAttachment = 0;
|
||||||
|
@ -58,12 +67,12 @@ namespace backend {
|
||||||
public:
|
public:
|
||||||
RenderPassBuilder(DeviceBase* device);
|
RenderPassBuilder(DeviceBase* device);
|
||||||
|
|
||||||
bool WasConsumed() const;
|
|
||||||
|
|
||||||
// NXT API
|
// NXT API
|
||||||
RenderPassBase* GetResultImpl() override;
|
RenderPassBase* GetResultImpl() override;
|
||||||
void SetAttachmentCount(uint32_t attachmentCount);
|
void SetAttachmentCount(uint32_t attachmentCount);
|
||||||
void AttachmentSetFormat(uint32_t attachmentSlot, nxt::TextureFormat format);
|
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 SetSubpassCount(uint32_t subpassCount);
|
||||||
void SubpassSetColorAttachment(uint32_t subpass, uint32_t outputAttachmentLocation, uint32_t attachmentSlot);
|
void SubpassSetColorAttachment(uint32_t subpass, uint32_t outputAttachmentLocation, uint32_t attachmentSlot);
|
||||||
void SubpassSetDepthStencilAttachment(uint32_t subpass, uint32_t attachmentSlot);
|
void SubpassSetDepthStencilAttachment(uint32_t subpass, uint32_t attachmentSlot);
|
||||||
|
|
|
@ -52,6 +52,17 @@ namespace backend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TextureFormatHasDepthOrStencil(nxt::TextureFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case nxt::TextureFormat::R8G8B8A8Unorm:
|
||||||
|
return false;
|
||||||
|
case nxt::TextureFormat::D32FloatS8Uint:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// TextureBase
|
// TextureBase
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace backend {
|
||||||
uint32_t TextureFormatPixelSize(nxt::TextureFormat format);
|
uint32_t TextureFormatPixelSize(nxt::TextureFormat format);
|
||||||
bool TextureFormatHasDepth(nxt::TextureFormat format);
|
bool TextureFormatHasDepth(nxt::TextureFormat format);
|
||||||
bool TextureFormatHasStencil(nxt::TextureFormat format);
|
bool TextureFormatHasStencil(nxt::TextureFormat format);
|
||||||
|
bool TextureFormatHasDepthOrStencil(nxt::TextureFormat format);
|
||||||
|
|
||||||
class TextureBase : public RefCounted {
|
class TextureBase : public RefCounted {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -262,21 +262,59 @@ namespace d3d12 {
|
||||||
case Command::BeginRenderSubpass:
|
case Command::BeginRenderSubpass:
|
||||||
{
|
{
|
||||||
commands.NextCommand<BeginRenderSubpassCmd>();
|
commands.NextCommand<BeginRenderSubpassCmd>();
|
||||||
Framebuffer::OMSetRenderTargetArgs args = currentFramebuffer->GetSubpassOMSetRenderTargetArgs(currentSubpass);
|
const auto& subpass = currentRenderPass->GetSubpassInfo(currentSubpass);
|
||||||
|
|
||||||
// HACK(enga@google.com): Remove when clearing is implemented
|
Framebuffer::OMSetRenderTargetArgs args = currentFramebuffer->GetSubpassOMSetRenderTargetArgs(currentSubpass);
|
||||||
for (uint32_t index = 0; index < args.numRTVs; ++index) {
|
if (args.dsv.ptr) {
|
||||||
static const float clearColor[] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE, &args.dsv);
|
||||||
commandList->ClearRenderTargetView(args.RTVs[index], clearColor, 0, nullptr);
|
} else {
|
||||||
|
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args.dsv.ptr) {
|
// Clear framebuffer attachments as needed
|
||||||
// HACK(enga@google.com): Remove when clearing is implemented
|
|
||||||
commandList->ClearDepthStencilView(args.dsv, D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, 1.0, 0, 0, nullptr);
|
|
||||||
|
|
||||||
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs, FALSE, &args.dsv);
|
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
|
||||||
} else {
|
uint32_t attachmentSlot = subpass.colorAttachments[location];
|
||||||
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs, FALSE, nullptr);
|
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachmentSlot);
|
||||||
|
|
||||||
|
// Only perform load op on first use
|
||||||
|
if (attachmentInfo.firstSubpass == currentSubpass) {
|
||||||
|
// Load op - color
|
||||||
|
if (attachmentInfo.colorLoadOp == nxt::LoadOp::Clear) {
|
||||||
|
auto handle = currentFramebuffer->GetDSVDescriptor(attachmentSlot);
|
||||||
|
const auto& clear = currentFramebuffer->GetClearColor(attachmentSlot);
|
||||||
|
commandList->ClearRenderTargetView(handle, clear.color, 0, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subpass.depthStencilAttachmentSet) {
|
||||||
|
uint32_t attachmentSlot = subpass.depthStencilAttachment;
|
||||||
|
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachmentSlot);
|
||||||
|
|
||||||
|
// Only perform load op on first use
|
||||||
|
if (attachmentInfo.firstSubpass == currentSubpass) {
|
||||||
|
// Load op - depth/stencil
|
||||||
|
bool doDepthClear = TextureFormatHasDepth(attachmentInfo.format) &&
|
||||||
|
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
|
||||||
|
bool doStencilClear = TextureFormatHasStencil(attachmentInfo.format) &&
|
||||||
|
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
|
||||||
|
|
||||||
|
D3D12_CLEAR_FLAGS clearFlags = {};
|
||||||
|
if (doDepthClear) {
|
||||||
|
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
|
||||||
|
}
|
||||||
|
if (doStencilClear) {
|
||||||
|
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
|
||||||
|
}
|
||||||
|
if (clearFlags) {
|
||||||
|
auto handle = currentFramebuffer->GetRTVDescriptor(attachmentSlot);
|
||||||
|
const auto& clear = currentFramebuffer->GetClearDepthStencil(attachmentSlot);
|
||||||
|
// TODO(kainino@chromium.org): investigate: should the NXT clear stencil type be uint8_t?
|
||||||
|
uint8_t clearStencil = static_cast<uint8_t>(clear.stencil);
|
||||||
|
commandList->ClearDepthStencilView(handle, clearFlags, clear.depth, clearStencil, 0, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr std::array<float, 4> defaultBlendFactor = { 0, 0, 0, 0 };
|
static constexpr std::array<float, 4> defaultBlendFactor = { 0, 0, 0, 0 };
|
||||||
|
|
|
@ -68,17 +68,26 @@ namespace d3d12 {
|
||||||
const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(subpassIndex);
|
const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(subpassIndex);
|
||||||
OMSetRenderTargetArgs args = {};
|
OMSetRenderTargetArgs args = {};
|
||||||
|
|
||||||
for (uint32_t index : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
for (uint32_t location : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
|
||||||
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.colorAttachments[index]];
|
uint32_t slot = subpassInfo.colorAttachments[location];
|
||||||
args.RTVs[args.numRTVs++] = rtvHeap.GetCPUHandle(heapIndex);
|
args.RTVs[args.numRTVs] = GetRTVDescriptor(slot);
|
||||||
|
args.numRTVs++;
|
||||||
}
|
}
|
||||||
if (subpassInfo.depthStencilAttachmentSet) {
|
if (subpassInfo.depthStencilAttachmentSet) {
|
||||||
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.depthStencilAttachment];
|
uint32_t slot = subpassInfo.depthStencilAttachment;
|
||||||
args.dsv = dsvHeap.GetCPUHandle(heapIndex);
|
args.dsv = GetDSVDescriptor(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE Framebuffer::GetRTVDescriptor(uint32_t attachmentSlot) {
|
||||||
|
return rtvHeap.GetCPUHandle(attachmentHeapIndices[attachmentSlot]);
|
||||||
|
}
|
||||||
|
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE Framebuffer::GetDSVDescriptor(uint32_t attachmentSlot) {
|
||||||
|
return dsvHeap.GetCPUHandle(attachmentHeapIndices[attachmentSlot]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "backend/d3d12/d3d12_platform.h"
|
#include "backend/d3d12/d3d12_platform.h"
|
||||||
#include "backend/d3d12/DescriptorHeapAllocator.h"
|
#include "backend/d3d12/DescriptorHeapAllocator.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace backend {
|
namespace backend {
|
||||||
|
@ -32,12 +33,14 @@ namespace d3d12 {
|
||||||
public:
|
public:
|
||||||
struct OMSetRenderTargetArgs {
|
struct OMSetRenderTargetArgs {
|
||||||
unsigned int numRTVs = 0;
|
unsigned int numRTVs = 0;
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE RTVs[kMaxColorAttachments] = {};
|
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, kMaxColorAttachments> RTVs = {};
|
||||||
D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
|
D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
Framebuffer(Device* device, FramebufferBuilder* builder);
|
Framebuffer(Device* device, FramebufferBuilder* builder);
|
||||||
OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs(uint32_t subpassIndex);
|
OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs(uint32_t subpassIndex);
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE GetRTVDescriptor(uint32_t attachmentSlot);
|
||||||
|
D3D12_CPU_DESCRIPTOR_HANDLE GetDSVDescriptor(uint32_t attachmentSlot);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Device* device = nullptr;
|
Device* device = nullptr;
|
||||||
|
|
|
@ -87,33 +87,61 @@ namespace metal {
|
||||||
const auto& info = currentRenderPass->GetSubpassInfo(subpass);
|
const auto& info = currentRenderPass->GetSubpassInfo(subpass);
|
||||||
|
|
||||||
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||||
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
|
for (unsigned int location : IterateBitSet(info.colorAttachmentsSet)) {
|
||||||
uint32_t attachment = info.colorAttachments[index];
|
uint32_t attachment = info.colorAttachments[location];
|
||||||
|
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachment);
|
||||||
|
|
||||||
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
||||||
auto texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
auto texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
||||||
descriptor.colorAttachments[index].texture = texture;
|
|
||||||
descriptor.colorAttachments[index].loadAction = MTLLoadActionLoad;
|
bool isFirstUse = attachmentInfo.firstSubpass == subpass;
|
||||||
descriptor.colorAttachments[index].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
|
bool shouldClearOnFirstUse = attachmentInfo.colorLoadOp == nxt::LoadOp::Clear;
|
||||||
descriptor.colorAttachments[index].storeAction = MTLStoreActionStore;
|
if (isFirstUse && shouldClearOnFirstUse) {
|
||||||
|
auto clearValue = currentFramebuffer->GetClearColor(location);
|
||||||
|
descriptor.colorAttachments[location].loadAction = MTLLoadActionClear;
|
||||||
|
descriptor.colorAttachments[location].clearColor = MTLClearColorMake(clearValue.color[0], clearValue.color[1], clearValue.color[2], clearValue.color[3]);
|
||||||
|
} else {
|
||||||
|
descriptor.colorAttachments[location].loadAction = MTLLoadActionLoad;
|
||||||
|
}
|
||||||
|
|
||||||
|
descriptor.colorAttachments[location].texture = texture;
|
||||||
|
descriptor.colorAttachments[location].storeAction = MTLStoreActionStore;
|
||||||
}
|
}
|
||||||
if (info.depthStencilAttachmentSet) {
|
if (info.depthStencilAttachmentSet) {
|
||||||
uint32_t attachment = info.depthStencilAttachment;
|
uint32_t attachment = info.depthStencilAttachment;
|
||||||
|
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachment);
|
||||||
|
|
||||||
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
||||||
id<MTLTexture> texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
id<MTLTexture> texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
|
||||||
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
|
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
|
||||||
|
|
||||||
|
bool isFirstUse = attachmentInfo.firstSubpass == subpass;
|
||||||
|
const auto& clearValues = currentFramebuffer->GetClearDepthStencil(attachment);
|
||||||
|
|
||||||
if (TextureFormatHasDepth(format)) {
|
if (TextureFormatHasDepth(format)) {
|
||||||
descriptor.depthAttachment.texture = texture;
|
descriptor.depthAttachment.texture = texture;
|
||||||
descriptor.depthAttachment.loadAction = MTLLoadActionClear;
|
|
||||||
descriptor.depthAttachment.clearDepth = 1.0;
|
|
||||||
descriptor.depthAttachment.storeAction = MTLStoreActionStore;
|
descriptor.depthAttachment.storeAction = MTLStoreActionStore;
|
||||||
|
|
||||||
|
bool shouldClearDepthOnFirstUse = attachmentInfo.depthLoadOp == nxt::LoadOp::Clear;
|
||||||
|
if (isFirstUse && shouldClearDepthOnFirstUse) {
|
||||||
|
descriptor.depthAttachment.loadAction = MTLLoadActionClear;
|
||||||
|
descriptor.depthAttachment.clearDepth = clearValues.depth;
|
||||||
|
} else {
|
||||||
|
descriptor.depthAttachment.loadAction = MTLLoadActionLoad;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (TextureFormatHasStencil(format)) {
|
if (TextureFormatHasStencil(format)) {
|
||||||
descriptor.stencilAttachment.texture = texture;
|
descriptor.stencilAttachment.texture = texture;
|
||||||
descriptor.stencilAttachment.loadAction = MTLLoadActionClear;
|
|
||||||
descriptor.stencilAttachment.clearStencil = 0;
|
|
||||||
descriptor.stencilAttachment.storeAction = MTLStoreActionStore;
|
descriptor.stencilAttachment.storeAction = MTLStoreActionStore;
|
||||||
|
|
||||||
|
bool shouldClearStencilOnFirstUse = attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear;
|
||||||
|
if (isFirstUse && shouldClearStencilOnFirstUse) {
|
||||||
|
descriptor.stencilAttachment.loadAction = MTLLoadActionClear;
|
||||||
|
descriptor.stencilAttachment.clearStencil = clearValues.stencil;
|
||||||
|
} else {
|
||||||
|
descriptor.stencilAttachment.loadAction = MTLLoadActionLoad;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,8 @@ namespace opengl {
|
||||||
case Command::BeginRenderSubpass:
|
case Command::BeginRenderSubpass:
|
||||||
{
|
{
|
||||||
commands.NextCommand<BeginRenderSubpassCmd>();
|
commands.NextCommand<BeginRenderSubpassCmd>();
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
// TODO(kainino@chromium.org): possible future
|
// TODO(kainino@chromium.org): possible future
|
||||||
// optimization: create these framebuffers at
|
// optimization: create these framebuffers at
|
||||||
// Framebuffer build time (or maybe CommandBuffer build
|
// Framebuffer build time (or maybe CommandBuffer build
|
||||||
|
@ -104,31 +106,42 @@ namespace opengl {
|
||||||
glGenFramebuffers(1, ¤tFBO);
|
glGenFramebuffers(1, ¤tFBO);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
|
||||||
|
|
||||||
const auto& info = currentRenderPass->GetSubpassInfo(currentSubpass);
|
const auto& subpass = currentRenderPass->GetSubpassInfo(currentSubpass);
|
||||||
|
|
||||||
|
// Mapping from attachmentSlot to GL framebuffer
|
||||||
|
// attachment points. Defaults to zero (GL_NONE).
|
||||||
|
std::array<GLenum, kMaxColorAttachments> drawBuffers = {};
|
||||||
|
|
||||||
|
// Construct GL framebuffer
|
||||||
|
|
||||||
std::array<GLenum, kMaxColorAttachments> drawBuffers;
|
|
||||||
drawBuffers.fill(GL_NONE);
|
|
||||||
unsigned int attachmentCount = 0;
|
unsigned int attachmentCount = 0;
|
||||||
for (unsigned int attachmentSlot : IterateBitSet(info.colorAttachmentsSet)) {
|
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
|
||||||
uint32_t attachment = info.colorAttachments[attachmentSlot];
|
uint32_t attachment = subpass.colorAttachments[location];
|
||||||
|
|
||||||
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
||||||
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
|
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
|
||||||
|
|
||||||
|
// Attach color buffers.
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
||||||
GL_COLOR_ATTACHMENT0 + attachmentSlot,
|
GL_COLOR_ATTACHMENT0 + location,
|
||||||
GL_TEXTURE_2D, texture, 0);
|
GL_TEXTURE_2D, texture, 0);
|
||||||
drawBuffers[attachmentSlot] = GL_COLOR_ATTACHMENT0 + attachmentSlot;
|
drawBuffers[location] = GL_COLOR_ATTACHMENT0 + location;
|
||||||
attachmentCount = attachmentSlot + 1;
|
attachmentCount = location + 1;
|
||||||
|
|
||||||
|
// TODO(kainino@chromium.org): the color clears (later in
|
||||||
|
// this function) may be undefined for other texture formats.
|
||||||
|
ASSERT(textureView->GetTexture()->GetFormat() == nxt::TextureFormat::R8G8B8A8Unorm);
|
||||||
}
|
}
|
||||||
glDrawBuffers(attachmentCount, &drawBuffers[0]);
|
glDrawBuffers(attachmentCount, drawBuffers.data());
|
||||||
|
|
||||||
if (info.depthStencilAttachmentSet) {
|
if (subpass.depthStencilAttachmentSet) {
|
||||||
uint32_t attachment = info.depthStencilAttachment;
|
uint32_t attachmentSlot = subpass.depthStencilAttachment;
|
||||||
|
|
||||||
auto textureView = currentFramebuffer->GetTextureView(attachment);
|
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();
|
||||||
|
|
||||||
|
// Attach depth/stencil buffer.
|
||||||
GLenum glAttachment = 0;
|
GLenum glAttachment = 0;
|
||||||
// TODO(kainino@chromium.org): it may be valid to just always use GL_DEPTH_STENCIL_ATTACHMENT here.
|
// TODO(kainino@chromium.org): it may be valid to just always use GL_DEPTH_STENCIL_ATTACHMENT here.
|
||||||
if (TextureFormatHasDepth(format)) {
|
if (TextureFormatHasDepth(format)) {
|
||||||
|
@ -141,12 +154,50 @@ namespace opengl {
|
||||||
glAttachment = GL_STENCIL_ATTACHMENT;
|
glAttachment = GL_STENCIL_ATTACHMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
|
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment, GL_TEXTURE_2D, texture, 0);
|
||||||
glAttachment, GL_TEXTURE_2D, texture, 0);
|
|
||||||
// Load action
|
// TODO(kainino@chromium.org): the depth/stencil clears (later in
|
||||||
glClearStencil(0);
|
// this function) may be undefined for other texture formats.
|
||||||
glClearDepth(1.0);
|
ASSERT(format == nxt::TextureFormat::D32FloatS8Uint);
|
||||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
}
|
||||||
|
|
||||||
|
// Clear framebuffer attachments as needed
|
||||||
|
|
||||||
|
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
|
||||||
|
uint32_t attachmentSlot = subpass.colorAttachments[location];
|
||||||
|
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachmentSlot);
|
||||||
|
|
||||||
|
// Only perform load op on first use
|
||||||
|
if (attachmentInfo.firstSubpass == currentSubpass) {
|
||||||
|
// Load op - color
|
||||||
|
if (attachmentInfo.colorLoadOp == nxt::LoadOp::Clear) {
|
||||||
|
const auto& clear = currentFramebuffer->GetClearColor(location);
|
||||||
|
glClearBufferfv(GL_COLOR, location, clear.color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subpass.depthStencilAttachmentSet) {
|
||||||
|
uint32_t attachmentSlot = subpass.depthStencilAttachment;
|
||||||
|
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachmentSlot);
|
||||||
|
|
||||||
|
// Only perform load op on first use
|
||||||
|
if (attachmentInfo.firstSubpass == currentSubpass) {
|
||||||
|
// Load op - depth/stencil
|
||||||
|
const auto& clear = currentFramebuffer->GetClearDepthStencil(subpass.depthStencilAttachment);
|
||||||
|
bool doDepthClear = TextureFormatHasDepth(attachmentInfo.format) &&
|
||||||
|
(attachmentInfo.depthLoadOp == nxt::LoadOp::Clear);
|
||||||
|
bool doStencilClear = TextureFormatHasStencil(attachmentInfo.format) &&
|
||||||
|
(attachmentInfo.stencilLoadOp == nxt::LoadOp::Clear);
|
||||||
|
if (doDepthClear && doStencilClear) {
|
||||||
|
glClearBufferfi(GL_DEPTH_STENCIL, 0, clear.depth, clear.stencil);
|
||||||
|
} else if (doDepthClear) {
|
||||||
|
glClearBufferfv(GL_DEPTH, 0, &clear.depth);
|
||||||
|
} else if (doStencilClear) {
|
||||||
|
const GLint clearStencil = clear.stencil;
|
||||||
|
glClearBufferiv(GL_STENCIL, 0, &clearStencil);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glBlendColor(0, 0, 0, 0);
|
glBlendColor(0, 0, 0, 0);
|
||||||
|
|
|
@ -16,8 +16,8 @@
|
||||||
|
|
||||||
#include "backend/opengl/BlendStateGL.h"
|
#include "backend/opengl/BlendStateGL.h"
|
||||||
#include "backend/opengl/DepthStencilStateGL.h"
|
#include "backend/opengl/DepthStencilStateGL.h"
|
||||||
#include "backend/opengl/PersistentPipelineStateGL.h"
|
|
||||||
#include "backend/opengl/OpenGLBackend.h"
|
#include "backend/opengl/OpenGLBackend.h"
|
||||||
|
#include "backend/opengl/PersistentPipelineStateGL.h"
|
||||||
|
|
||||||
namespace backend {
|
namespace backend {
|
||||||
namespace opengl {
|
namespace opengl {
|
||||||
|
|
|
@ -103,21 +103,6 @@ namespace utils {
|
||||||
currentTexture = currentDrawable.texture;
|
currentTexture = currentDrawable.texture;
|
||||||
[currentTexture retain];
|
[currentTexture retain];
|
||||||
|
|
||||||
// Clear initial contents of the texture
|
|
||||||
{
|
|
||||||
MTLRenderPassDescriptor* passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
|
||||||
passDescriptor.colorAttachments[0].texture = currentTexture;
|
|
||||||
passDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
|
|
||||||
passDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
|
|
||||||
passDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
|
|
||||||
|
|
||||||
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
|
|
||||||
id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer
|
|
||||||
renderCommandEncoderWithDescriptor:passDescriptor];
|
|
||||||
[commandEncoder endEncoding];
|
|
||||||
[commandBuffer commit];
|
|
||||||
}
|
|
||||||
|
|
||||||
nextTexture->texture = reinterpret_cast<void*>(currentTexture);
|
nextTexture->texture = reinterpret_cast<void*>(currentTexture);
|
||||||
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
|
|
|
@ -54,12 +54,6 @@ namespace utils {
|
||||||
glDeleteFramebuffers(1, &backFBO);
|
glDeleteFramebuffers(1, &backFBO);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HACKCLEAR() {
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backFBO);
|
|
||||||
glClearColor(0, 0, 0, 1);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For GenerateSwapChainImplementation
|
// For GenerateSwapChainImplementation
|
||||||
friend class SwapChainImpl;
|
friend class SwapChainImpl;
|
||||||
|
|
||||||
|
@ -89,8 +83,6 @@ namespace utils {
|
||||||
// Reallocate the texture
|
// Reallocate the texture
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
|
||||||
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
// Clear the newly (re-)allocated texture
|
|
||||||
HACKCLEAR();
|
|
||||||
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +98,6 @@ namespace utils {
|
||||||
glBlitFramebuffer(0, 0, cfgWidth, cfgHeight, 0, 0, cfgWidth, cfgHeight,
|
glBlitFramebuffer(0, 0, cfgWidth, cfgHeight, 0, 0, cfgWidth, cfgHeight,
|
||||||
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
HACKCLEAR();
|
|
||||||
|
|
||||||
return NXT_SWAP_CHAIN_NO_ERROR;
|
return NXT_SWAP_CHAIN_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue