Load operations (#105)

* load ops: design + implementation (all backends)

* Animometer/glTFViewer: use just one subpass per frame
This commit is contained in:
Kai Ninomiya
2017-08-11 14:36:20 -07:00
committed by GitHub
parent 3d1154786f
commit b985431c82
18 changed files with 380 additions and 102 deletions

View File

@@ -25,16 +25,32 @@ namespace backend {
// Framebuffer
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() {
return renderPass.Get();
}
TextureViewBase* FramebufferBase::GetTextureView(uint32_t index) {
ASSERT(index < textureViews.size());
return textureViews[index].Get();
TextureViewBase* FramebufferBase::GetTextureView(uint32_t attachmentSlot) {
ASSERT(attachmentSlot < textureViews.size());
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 {
@@ -45,6 +61,30 @@ namespace backend {
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
enum FramebufferSetProperties {

View File

@@ -28,18 +28,37 @@ 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 index);
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* device;
Ref<RenderPassBase> renderPass;
uint32_t width = 0;
uint32_t height = 0;
std::vector<Ref<TextureViewBase>> textureViews;
std::vector<ClearColor> clearColors;
std::vector<ClearDepthStencil> clearDepthStencils;
};
class FramebufferBuilder : public Builder<FramebufferBase> {

View File

@@ -18,6 +18,7 @@
#include "backend/Device.h"
#include "backend/Texture.h"
#include "common/Assert.h"
#include "common/BitSetIterator.h"
namespace backend {
@@ -25,6 +26,23 @@ namespace backend {
RenderPassBase::RenderPassBase(RenderPassBuilder* builder)
: 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 {
@@ -95,8 +113,8 @@ namespace backend {
HandleError("Render pass attachment count not set yet");
return;
}
if (attachmentSlot > attachments.size()) {
HandleError("Render pass attachment index out of bounds");
if (attachmentSlot >= attachments.size()) {
HandleError("Render pass attachment slot out of bounds");
return;
}
if (attachmentProperties[attachmentSlot][ATTACHMENT_PROPERTY_FORMAT]) {
@@ -108,6 +126,34 @@ namespace backend {
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) {
if ((propertiesSet & RENDERPASS_PROPERTY_SUBPASS_COUNT) != 0) {
HandleError("Render pass subpass count property set multiple times");

View File

@@ -34,10 +34,19 @@ namespace backend {
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;
@@ -58,12 +67,12 @@ namespace backend {
public:
RenderPassBuilder(DeviceBase* device);
bool WasConsumed() const;
// 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);

View File

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

View File

@@ -26,6 +26,7 @@ namespace backend {
uint32_t TextureFormatPixelSize(nxt::TextureFormat format);
bool TextureFormatHasDepth(nxt::TextureFormat format);
bool TextureFormatHasStencil(nxt::TextureFormat format);
bool TextureFormatHasDepthOrStencil(nxt::TextureFormat format);
class TextureBase : public RefCounted {
public:

View File

@@ -262,21 +262,59 @@ namespace d3d12 {
case Command::BeginRenderSubpass:
{
commands.NextCommand<BeginRenderSubpassCmd>();
Framebuffer::OMSetRenderTargetArgs args = currentFramebuffer->GetSubpassOMSetRenderTargetArgs(currentSubpass);
const auto& subpass = currentRenderPass->GetSubpassInfo(currentSubpass);
// HACK(enga@google.com): Remove when clearing is implemented
for (uint32_t index = 0; index < args.numRTVs; ++index) {
static const float clearColor[] = { 0.0f, 0.0f, 0.0f, 0.0f };
commandList->ClearRenderTargetView(args.RTVs[index], clearColor, 0, nullptr);
Framebuffer::OMSetRenderTargetArgs args = currentFramebuffer->GetSubpassOMSetRenderTargetArgs(currentSubpass);
if (args.dsv.ptr) {
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE, &args.dsv);
} else {
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs.data(), FALSE, nullptr);
}
if (args.dsv.ptr) {
// 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);
// Clear framebuffer attachments as needed
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs, FALSE, &args.dsv);
} else {
commandList->OMSetRenderTargets(args.numRTVs, args.RTVs, FALSE, nullptr);
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) {
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 };

View File

@@ -68,17 +68,26 @@ namespace d3d12 {
const auto& subpassInfo = GetRenderPass()->GetSubpassInfo(subpassIndex);
OMSetRenderTargetArgs args = {};
for (uint32_t index : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.colorAttachments[index]];
args.RTVs[args.numRTVs++] = rtvHeap.GetCPUHandle(heapIndex);
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 heapIndex = attachmentHeapIndices[subpassInfo.depthStencilAttachment];
args.dsv = dsvHeap.GetCPUHandle(heapIndex);
uint32_t slot = subpassInfo.depthStencilAttachment;
args.dsv = GetDSVDescriptor(slot);
}
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]);
}
}
}

View File

@@ -21,6 +21,7 @@
#include "backend/d3d12/d3d12_platform.h"
#include "backend/d3d12/DescriptorHeapAllocator.h"
#include <array>
#include <vector>
namespace backend {
@@ -32,12 +33,14 @@ namespace d3d12 {
public:
struct OMSetRenderTargetArgs {
unsigned int numRTVs = 0;
D3D12_CPU_DESCRIPTOR_HANDLE RTVs[kMaxColorAttachments] = {};
std::array<D3D12_CPU_DESCRIPTOR_HANDLE, kMaxColorAttachments> RTVs = {};
D3D12_CPU_DESCRIPTOR_HANDLE dsv = {};
};
Framebuffer(Device* device, FramebufferBuilder* builder);
OMSetRenderTargetArgs GetSubpassOMSetRenderTargetArgs(uint32_t subpassIndex);
D3D12_CPU_DESCRIPTOR_HANDLE GetRTVDescriptor(uint32_t attachmentSlot);
D3D12_CPU_DESCRIPTOR_HANDLE GetDSVDescriptor(uint32_t attachmentSlot);
private:
Device* device = nullptr;

View File

@@ -87,33 +87,61 @@ namespace metal {
const auto& info = currentRenderPass->GetSubpassInfo(subpass);
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
uint32_t attachment = info.colorAttachments[index];
for (unsigned int location : IterateBitSet(info.colorAttachmentsSet)) {
uint32_t attachment = info.colorAttachments[location];
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachment);
auto textureView = currentFramebuffer->GetTextureView(attachment);
auto texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
descriptor.colorAttachments[index].texture = texture;
descriptor.colorAttachments[index].loadAction = MTLLoadActionLoad;
descriptor.colorAttachments[index].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);
descriptor.colorAttachments[index].storeAction = MTLStoreActionStore;
bool isFirstUse = attachmentInfo.firstSubpass == subpass;
bool shouldClearOnFirstUse = attachmentInfo.colorLoadOp == nxt::LoadOp::Clear;
if (isFirstUse && shouldClearOnFirstUse) {
auto clearValue = currentFramebuffer->GetClearColor(location);
descriptor.colorAttachments[location].loadAction = MTLLoadActionClear;
descriptor.colorAttachments[location].clearColor = MTLClearColorMake(clearValue.color[0], clearValue.color[1], clearValue.color[2], clearValue.color[3]);
} else {
descriptor.colorAttachments[location].loadAction = MTLLoadActionLoad;
}
descriptor.colorAttachments[location].texture = texture;
descriptor.colorAttachments[location].storeAction = MTLStoreActionStore;
}
if (info.depthStencilAttachmentSet) {
uint32_t attachment = info.depthStencilAttachment;
const auto& attachmentInfo = currentRenderPass->GetAttachmentInfo(attachment);
auto textureView = currentFramebuffer->GetTextureView(attachment);
id<MTLTexture> texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
bool isFirstUse = attachmentInfo.firstSubpass == subpass;
const auto& clearValues = currentFramebuffer->GetClearDepthStencil(attachment);
if (TextureFormatHasDepth(format)) {
descriptor.depthAttachment.texture = texture;
descriptor.depthAttachment.loadAction = MTLLoadActionClear;
descriptor.depthAttachment.clearDepth = 1.0;
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)) {
descriptor.stencilAttachment.texture = texture;
descriptor.stencilAttachment.loadAction = MTLLoadActionClear;
descriptor.stencilAttachment.clearStencil = 0;
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;
}
}
}

View File

@@ -96,6 +96,8 @@ namespace opengl {
case Command::BeginRenderSubpass:
{
commands.NextCommand<BeginRenderSubpassCmd>();
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
// TODO(kainino@chromium.org): possible future
// optimization: create these framebuffers at
// Framebuffer build time (or maybe CommandBuffer build
@@ -104,31 +106,42 @@ namespace opengl {
glGenFramebuffers(1, &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;
for (unsigned int attachmentSlot : IterateBitSet(info.colorAttachmentsSet)) {
uint32_t attachment = info.colorAttachments[attachmentSlot];
for (unsigned int location : IterateBitSet(subpass.colorAttachmentsSet)) {
uint32_t attachment = subpass.colorAttachments[location];
auto textureView = currentFramebuffer->GetTextureView(attachment);
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
// Attach color buffers.
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0 + attachmentSlot,
GL_TEXTURE_2D, texture, 0);
drawBuffers[attachmentSlot] = GL_COLOR_ATTACHMENT0 + attachmentSlot;
attachmentCount = attachmentSlot + 1;
GL_COLOR_ATTACHMENT0 + location,
GL_TEXTURE_2D, texture, 0);
drawBuffers[location] = GL_COLOR_ATTACHMENT0 + location;
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) {
uint32_t attachment = info.depthStencilAttachment;
if (subpass.depthStencilAttachmentSet) {
uint32_t attachmentSlot = subpass.depthStencilAttachment;
auto textureView = currentFramebuffer->GetTextureView(attachment);
auto textureView = currentFramebuffer->GetTextureView(attachmentSlot);
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
// Attach depth/stencil buffer.
GLenum glAttachment = 0;
// TODO(kainino@chromium.org): it may be valid to just always use GL_DEPTH_STENCIL_ATTACHMENT here.
if (TextureFormatHasDepth(format)) {
@@ -141,12 +154,50 @@ namespace opengl {
glAttachment = GL_STENCIL_ATTACHMENT;
}
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
glAttachment, GL_TEXTURE_2D, texture, 0);
// Load action
glClearStencil(0);
glClearDepth(1.0);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, glAttachment, GL_TEXTURE_2D, texture, 0);
// TODO(kainino@chromium.org): the depth/stencil clears (later in
// this function) may be undefined for other texture formats.
ASSERT(format == nxt::TextureFormat::D32FloatS8Uint);
}
// 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);

View File

@@ -16,8 +16,8 @@
#include "backend/opengl/BlendStateGL.h"
#include "backend/opengl/DepthStencilStateGL.h"
#include "backend/opengl/PersistentPipelineStateGL.h"
#include "backend/opengl/OpenGLBackend.h"
#include "backend/opengl/PersistentPipelineStateGL.h"
namespace backend {
namespace opengl {

View File

@@ -103,21 +103,6 @@ namespace utils {
currentTexture = currentDrawable.texture;
[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);
return NXT_SWAP_CHAIN_NO_ERROR;

View File

@@ -54,12 +54,6 @@ namespace utils {
glDeleteFramebuffers(1, &backFBO);
}
void HACKCLEAR() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backFBO);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
// For GenerateSwapChainImplementation
friend class SwapChainImpl;
@@ -89,8 +83,6 @@ namespace utils {
// Reallocate the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// Clear the newly (re-)allocated texture
HACKCLEAR();
return NXT_SWAP_CHAIN_NO_ERROR;
}
@@ -106,7 +98,6 @@ namespace utils {
glBlitFramebuffer(0, 0, cfgWidth, cfgHeight, 0, 0, cfgWidth, cfgHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glfwSwapBuffers(window);
HACKCLEAR();
return NXT_SWAP_CHAIN_NO_ERROR;
}