feat: support rect clears for camera viewport rendering

This commit is contained in:
2026-04-01 15:16:25 +08:00
parent d85b2ca056
commit e03f17146a
11 changed files with 695 additions and 160 deletions

View File

@@ -102,10 +102,19 @@ public:
void DrawIndexedInstancedIndirectInternal(ID3D12Resource* argBuffer, uint64_t alignedByteOffset);
void Clear(float r, float g, float b, float a, uint32_t buffers) override;
void ClearRenderTarget(RHIResourceView* renderTarget, const float color[4]) override;
void ClearRenderTarget(
RHIResourceView* renderTarget,
const float color[4],
uint32_t rectCount = 0,
const Rect* rects = nullptr) override;
void ClearRenderTargetView(ID3D12Resource* renderTarget, const float color[4], uint32_t rectCount = 0, const D3D12_RECT* rects = nullptr);
void ClearRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE renderTargetHandle, const float color[4], uint32_t rectCount = 0, const D3D12_RECT* rects = nullptr);
void ClearDepthStencil(RHIResourceView* depthStencil, float depth, uint8_t stencil) override;
void ClearDepthStencil(
RHIResourceView* depthStencil,
float depth,
uint8_t stencil,
uint32_t rectCount = 0,
const Rect* rects = nullptr) override;
void ClearDepthStencilView(ID3D12Resource* depthStencil, uint32_t clearFlags, float depth = 1.0f, uint8_t stencil = 0, uint32_t rectCount = 0, const D3D12_RECT* rects = nullptr);
void ClearDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE depthStencilHandle, uint32_t clearFlags, float depth = 1.0f, uint8_t stencil = 0, uint32_t rectCount = 0, const D3D12_RECT* rects = nullptr);
void ClearUnorderedAccessView(D3D12_GPU_DESCRIPTOR_HANDLE viewHandle, D3D12_CPU_DESCRIPTOR_HANDLE resourceHandle, ID3D12Resource* unorderedAccess, const float values[4], uint32_t rectCount = 0, const D3D12_RECT* rects = nullptr);
@@ -154,4 +163,4 @@ private:
};
} // namespace RHI
} // namespace XCEngine
} // namespace XCEngine

View File

@@ -192,8 +192,17 @@ public:
void SetRenderTargets(uint32_t count, RHIResourceView** renderTargets, RHIResourceView* depthStencil = nullptr) override;
void SetStencilRef(uint8_t ref) override;
void SetBlendFactor(const float factor[4]) override;
void ClearRenderTarget(RHIResourceView* renderTarget, const float color[4]) override;
void ClearDepthStencil(RHIResourceView* depthStencil, float depth, uint8_t stencil) override;
void ClearRenderTarget(
RHIResourceView* renderTarget,
const float color[4],
uint32_t rectCount = 0,
const Rect* rects = nullptr) override;
void ClearDepthStencil(
RHIResourceView* depthStencil,
float depth,
uint8_t stencil,
uint32_t rectCount = 0,
const Rect* rects = nullptr) override;
void Draw(uint32_t vertexCount, uint32_t instanceCount, uint32_t startVertex, uint32_t startInstance) override;
void DrawIndexed(uint32_t indexCount, uint32_t instanceCount, uint32_t startIndex, int32_t baseVertex, uint32_t startInstance) override;
@@ -212,6 +221,8 @@ private:
std::vector<unsigned int> m_enabledVertexAttributes;
OpenGLShader* m_currentShader;
OpenGLFramebuffer* m_composedFramebuffer;
uint32_t m_currentRenderTargetWidth;
uint32_t m_currentRenderTargetHeight;
};
} // namespace RHI

View File

@@ -92,8 +92,17 @@ public:
virtual void DrawIndexed(uint32_t indexCount, uint32_t instanceCount = 1, uint32_t startIndex = 0, int32_t baseVertex = 0, uint32_t startInstance = 0) = 0;
virtual void Clear(float r, float g, float b, float a, uint32_t buffers) = 0;
virtual void ClearRenderTarget(RHIResourceView* renderTarget, const float color[4]) = 0;
virtual void ClearDepthStencil(RHIResourceView* depthStencil, float depth, uint8_t stencil) = 0;
virtual void ClearRenderTarget(
RHIResourceView* renderTarget,
const float color[4],
uint32_t rectCount = 0,
const Rect* rects = nullptr) = 0;
virtual void ClearDepthStencil(
RHIResourceView* depthStencil,
float depth,
uint8_t stencil,
uint32_t rectCount = 0,
const Rect* rects = nullptr) = 0;
virtual void CopyResource(RHIResourceView* dst, RHIResourceView* src) = 0;

View File

@@ -52,8 +52,17 @@ public:
void DrawIndexed(uint32_t indexCount, uint32_t instanceCount = 1, uint32_t startIndex = 0, int32_t baseVertex = 0, uint32_t startInstance = 0) override;
void Clear(float r, float g, float b, float a, uint32_t buffers) override;
void ClearRenderTarget(RHIResourceView* renderTarget, const float color[4]) override;
void ClearDepthStencil(RHIResourceView* depthStencil, float depth, uint8_t stencil) override;
void ClearRenderTarget(
RHIResourceView* renderTarget,
const float color[4],
uint32_t rectCount = 0,
const Rect* rects = nullptr) override;
void ClearDepthStencil(
RHIResourceView* depthStencil,
float depth,
uint8_t stencil,
uint32_t rectCount = 0,
const Rect* rects = nullptr) override;
void CopyResource(RHIResourceView* dst, RHIResourceView* src) override;
void Dispatch(uint32_t x, uint32_t y, uint32_t z) override;

View File

@@ -9,6 +9,7 @@
#include "XCEngine/RHI/D3D12/D3D12DescriptorSet.h"
#include <algorithm>
#include <vector>
namespace XCEngine {
namespace RHI {
@@ -765,16 +766,54 @@ void D3D12CommandList::Clear(float r, float g, float b, float a, uint32_t buffer
}
}
void D3D12CommandList::ClearRenderTarget(RHIResourceView* renderTarget, const float color[4]) {
void D3D12CommandList::ClearRenderTarget(RHIResourceView* renderTarget, const float color[4], uint32_t rectCount, const Rect* rects) {
if (!renderTarget || !renderTarget->IsValid()) return;
D3D12ResourceView* view = static_cast<D3D12ResourceView*>(renderTarget);
ClearRenderTargetView(view->GetCPUHandle(), color, 0, nullptr);
std::vector<D3D12_RECT> nativeRects;
const D3D12_RECT* nativeRectData = nullptr;
if (rectCount > 0 && rects != nullptr) {
nativeRects.reserve(rectCount);
for (uint32_t i = 0; i < rectCount; ++i) {
nativeRects.push_back(D3D12_RECT{
rects[i].left,
rects[i].top,
rects[i].right,
rects[i].bottom
});
}
nativeRectData = nativeRects.data();
}
ClearRenderTargetView(view->GetCPUHandle(), color, static_cast<uint32_t>(nativeRects.size()), nativeRectData);
}
void D3D12CommandList::ClearDepthStencil(RHIResourceView* depthStencil, float depth, uint8_t stencil) {
void D3D12CommandList::ClearDepthStencil(RHIResourceView* depthStencil, float depth, uint8_t stencil, uint32_t rectCount, const Rect* rects) {
if (!depthStencil || !depthStencil->IsValid()) return;
D3D12ResourceView* view = static_cast<D3D12ResourceView*>(depthStencil);
ClearDepthStencilView(view->GetCPUHandle(), D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL, depth, stencil, 0, nullptr);
std::vector<D3D12_RECT> nativeRects;
const D3D12_RECT* nativeRectData = nullptr;
if (rectCount > 0 && rects != nullptr) {
nativeRects.reserve(rectCount);
for (uint32_t i = 0; i < rectCount; ++i) {
nativeRects.push_back(D3D12_RECT{
rects[i].left,
rects[i].top,
rects[i].right,
rects[i].bottom
});
}
nativeRectData = nativeRects.data();
}
ClearDepthStencilView(
view->GetCPUHandle(),
D3D12_CLEAR_FLAG_DEPTH | D3D12_CLEAR_FLAG_STENCIL,
depth,
stencil,
static_cast<uint32_t>(nativeRects.size()),
nativeRectData);
}
void D3D12CommandList::ClearDepthStencilView(ID3D12Resource* depthStencil, uint32_t clearFlags, float depth, uint8_t stencil, uint32_t rectCount, const D3D12_RECT* rects) {

View File

@@ -27,6 +27,41 @@ struct OpenGLVertexAttribFormat {
bool integer = false;
};
bool ClampOpenGLClearRect(const Rect& rect, GLsizei width, GLsizei height, GLint& x, GLint& y, GLsizei& outWidth, GLsizei& outHeight) {
if (width <= 0 || height <= 0) {
return false;
}
const GLint left = std::clamp(rect.left, 0, static_cast<int32_t>(width));
const GLint right = std::clamp(rect.right, 0, static_cast<int32_t>(width));
const GLint top = std::clamp(rect.top, 0, static_cast<int32_t>(height));
const GLint bottom = std::clamp(rect.bottom, 0, static_cast<int32_t>(height));
if (right <= left || bottom <= top) {
return false;
}
x = left;
y = static_cast<GLint>(height) - bottom;
outWidth = right - left;
outHeight = bottom - top;
return outWidth > 0 && outHeight > 0;
}
bool GetOpenGLClearTargetExtent(const OpenGLResourceView* view, GLsizei& width, GLsizei& height) {
if (view == nullptr) {
return false;
}
const OpenGLTexture* texture = view->GetTextureResource();
if (texture == nullptr) {
return false;
}
width = static_cast<GLsizei>(texture->GetWidth());
height = static_cast<GLsizei>(texture->GetHeight());
return width > 0 && height > 0;
}
bool GetOpenGLVertexAttribFormat(Format format, OpenGLVertexAttribFormat& attributeFormat) {
switch (format) {
case Format::R8_UNorm:
@@ -50,6 +85,9 @@ bool GetOpenGLVertexAttribFormat(Format format, OpenGLVertexAttribFormat& attrib
case Format::R32G32_Float:
attributeFormat = { 2, GL_FLOAT, GL_FALSE, false };
return true;
case Format::R32G32B32_Float:
attributeFormat = { 3, GL_FLOAT, GL_FALSE, false };
return true;
case Format::R32G32B32A32_Float:
attributeFormat = { 4, GL_FLOAT, GL_FALSE, false };
return true;
@@ -99,7 +137,9 @@ OpenGLCommandList::OpenGLCommandList()
, m_currentIndexOffset(0)
, m_currentPipelineState(nullptr)
, m_currentShader(nullptr)
, m_composedFramebuffer(nullptr) {
, m_composedFramebuffer(nullptr)
, m_currentRenderTargetWidth(0)
, m_currentRenderTargetHeight(0) {
}
OpenGLCommandList::~OpenGLCommandList() {
@@ -510,6 +550,8 @@ void OpenGLCommandList::Shutdown() {
}
m_currentPipelineState = nullptr;
m_currentShader = nullptr;
m_currentRenderTargetWidth = 0;
m_currentRenderTargetHeight = 0;
}
void OpenGLCommandList::Reset() {
@@ -517,6 +559,8 @@ void OpenGLCommandList::Reset() {
m_currentPipelineState = nullptr;
m_currentIndexOffset = 0;
m_currentIndexType = GL_UNSIGNED_INT;
m_currentRenderTargetWidth = 0;
m_currentRenderTargetHeight = 0;
}
void OpenGLCommandList::Close() {
@@ -589,6 +633,8 @@ void OpenGLCommandList::BeginRenderPass(RHIRenderPass* renderPass, RHIFramebuffe
OpenGLFramebuffer* glFramebuffer = static_cast<OpenGLFramebuffer*>(framebuffer);
glFramebuffer->Bind();
m_currentRenderTargetWidth = glFramebuffer->GetWidth();
m_currentRenderTargetHeight = glFramebuffer->GetHeight();
if (!renderPass) return;
@@ -621,15 +667,23 @@ void OpenGLCommandList::EndRenderPass() {
}
void OpenGLCommandList::SetViewport(const Viewport& viewport) {
glViewport(static_cast<int>(viewport.topLeftX), static_cast<int>(viewport.topLeftY),
static_cast<int>(viewport.width), static_cast<int>(viewport.height));
const int width = static_cast<int>(viewport.width);
const int height = static_cast<int>(viewport.height);
const int x = static_cast<int>(viewport.topLeftX);
int y = static_cast<int>(viewport.topLeftY);
if (m_currentRenderTargetHeight > 0) {
y = static_cast<int>(m_currentRenderTargetHeight) - (y + height);
}
glViewport(x, y, width, height);
}
void OpenGLCommandList::SetViewports(uint32_t count, const Viewport* viewports) {
std::vector<float> viewportsGL(count * 6);
for (uint32_t i = 0; i < count; ++i) {
viewportsGL[i * 6 + 0] = viewports[i].topLeftX;
viewportsGL[i * 6 + 1] = viewports[i].topLeftY;
viewportsGL[i * 6 + 1] = m_currentRenderTargetHeight > 0
? static_cast<float>(m_currentRenderTargetHeight) - (viewports[i].topLeftY + viewports[i].height)
: viewports[i].topLeftY;
viewportsGL[i * 6 + 2] = viewports[i].width;
viewportsGL[i * 6 + 3] = viewports[i].height;
viewportsGL[i * 6 + 4] = viewports[i].minDepth;
@@ -639,14 +693,22 @@ void OpenGLCommandList::SetViewports(uint32_t count, const Viewport* viewports)
}
void OpenGLCommandList::SetScissorRect(const Rect& rect) {
glScissor(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
const int width = rect.right - rect.left;
const int height = rect.bottom - rect.top;
int y = rect.top;
if (m_currentRenderTargetHeight > 0) {
y = static_cast<int>(m_currentRenderTargetHeight) - rect.bottom;
}
glScissor(rect.left, y, width, height);
}
void OpenGLCommandList::SetScissorRects(uint32_t count, const Rect* rects) {
std::vector<int> scissorGL(count * 4);
for (uint32_t i = 0; i < count; ++i) {
scissorGL[i * 4 + 0] = rects[i].left;
scissorGL[i * 4 + 1] = rects[i].top;
scissorGL[i * 4 + 1] = m_currentRenderTargetHeight > 0
? static_cast<int>(m_currentRenderTargetHeight) - rects[i].bottom
: rects[i].top;
scissorGL[i * 4 + 2] = rects[i].right - rects[i].left;
scissorGL[i * 4 + 3] = rects[i].bottom - rects[i].top;
}
@@ -654,6 +716,9 @@ void OpenGLCommandList::SetScissorRects(uint32_t count, const Rect* rects) {
}
void OpenGLCommandList::SetRenderTargets(uint32_t count, RHIResourceView** renderTargets, RHIResourceView* depthStencil) {
m_currentRenderTargetWidth = 0;
m_currentRenderTargetHeight = 0;
if (count > 0 && renderTargets != nullptr) {
const bool requiresComposedFramebuffer = count > 1 || depthStencil != nullptr;
std::vector<GLenum> drawBuffers(count, GL_NONE);
@@ -696,9 +761,16 @@ void OpenGLCommandList::SetRenderTargets(uint32_t count, RHIResourceView** rende
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_composedFramebuffer->GetFramebuffer());
m_currentRenderTargetWidth = width;
m_currentRenderTargetHeight = height;
} else {
ReleaseComposedFramebuffer();
OpenGLResourceView* view = static_cast<OpenGLResourceView*>(renderTargets[0]);
const OpenGLTexture* texture = view != nullptr ? view->GetTextureResource() : nullptr;
if (texture != nullptr) {
m_currentRenderTargetWidth = texture->GetWidth();
m_currentRenderTargetHeight = texture->GetHeight();
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, view != nullptr ? view->GetFramebuffer() : 0);
}
@@ -707,6 +779,11 @@ void OpenGLCommandList::SetRenderTargets(uint32_t count, RHIResourceView** rende
ReleaseComposedFramebuffer();
OpenGLResourceView* dsv = static_cast<OpenGLResourceView*>(depthStencil);
if (dsv && dsv->IsValid()) {
const OpenGLTexture* depthTexture = dsv->GetTextureResource();
if (depthTexture != nullptr) {
m_currentRenderTargetWidth = depthTexture->GetWidth();
m_currentRenderTargetHeight = depthTexture->GetHeight();
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dsv->GetFramebuffer());
}
glDrawBuffers(0, nullptr);
@@ -718,35 +795,114 @@ void OpenGLCommandList::SetRenderTargets(uint32_t count, RHIResourceView** rende
(void)depthStencil;
}
void OpenGLCommandList::ClearRenderTarget(RHIResourceView* renderTarget, const float color[4]) {
void OpenGLCommandList::ClearRenderTarget(RHIResourceView* renderTarget, const float color[4], uint32_t rectCount, const Rect* rects) {
if (!renderTarget) return;
OpenGLResourceView* view = static_cast<OpenGLResourceView*>(renderTarget);
if (!view->IsValid()) return;
GLuint prevFBO = 0;
GLint prevScissorBox[4] = {};
GLboolean prevScissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
GLboolean prevColorMask[4] = {};
GLfloat prevClearColor[4] = {};
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, reinterpret_cast<GLint*>(&prevFBO));
glGetIntegerv(GL_SCISSOR_BOX, prevScissorBox);
glGetBooleanv(GL_COLOR_WRITEMASK, prevColorMask);
glGetFloatv(GL_COLOR_CLEAR_VALUE, prevClearColor);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, view->GetFramebuffer());
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearColor(color[0], color[1], color[2], color[3]);
glClear(GL_COLOR_BUFFER_BIT);
GLsizei framebufferWidth = 0;
GLsizei framebufferHeight = 0;
if (rectCount > 0 && rects != nullptr && GetOpenGLClearTargetExtent(view, framebufferWidth, framebufferHeight)) {
glEnable(GL_SCISSOR_TEST);
for (uint32_t i = 0; i < rectCount; ++i) {
GLint x = 0;
GLint y = 0;
GLsizei width = 0;
GLsizei height = 0;
if (!ClampOpenGLClearRect(rects[i], framebufferWidth, framebufferHeight, x, y, width, height)) {
continue;
}
glScissor(x, y, width, height);
glClear(GL_COLOR_BUFFER_BIT);
}
} else {
glClear(GL_COLOR_BUFFER_BIT);
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFBO);
glClearColor(prevClearColor[0], prevClearColor[1], prevClearColor[2], prevClearColor[3]);
glColorMask(prevColorMask[0], prevColorMask[1], prevColorMask[2], prevColorMask[3]);
glScissor(prevScissorBox[0], prevScissorBox[1], prevScissorBox[2], prevScissorBox[3]);
if (prevScissorEnabled == GL_TRUE) {
glEnable(GL_SCISSOR_TEST);
} else {
glDisable(GL_SCISSOR_TEST);
}
}
void OpenGLCommandList::ClearDepthStencil(RHIResourceView* depthStencil, float depth, uint8_t stencil) {
void OpenGLCommandList::ClearDepthStencil(RHIResourceView* depthStencil, float depth, uint8_t stencil, uint32_t rectCount, const Rect* rects) {
if (!depthStencil) return;
OpenGLResourceView* view = static_cast<OpenGLResourceView*>(depthStencil);
if (!view->IsValid()) return;
GLuint prevFBO = 0;
GLint prevScissorBox[4] = {};
GLint prevStencilMaskFront = 0;
GLint prevStencilMaskBack = 0;
GLint prevStencilClear = 0;
GLboolean prevScissorEnabled = glIsEnabled(GL_SCISSOR_TEST);
GLboolean prevDepthMask = GL_TRUE;
GLdouble prevDepthClear = 1.0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, reinterpret_cast<GLint*>(&prevFBO));
glGetIntegerv(GL_SCISSOR_BOX, prevScissorBox);
glGetBooleanv(GL_DEPTH_WRITEMASK, &prevDepthMask);
glGetDoublev(GL_DEPTH_CLEAR_VALUE, &prevDepthClear);
glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &prevStencilClear);
glGetIntegerv(GL_STENCIL_WRITEMASK, &prevStencilMaskFront);
glGetIntegerv(GL_STENCIL_BACK_WRITEMASK, &prevStencilMaskBack);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, view->GetFramebuffer());
glDepthMask(GL_TRUE);
glStencilMaskSeparate(GL_FRONT, 0xFF);
glStencilMaskSeparate(GL_BACK, 0xFF);
glClearDepth(depth);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glClearStencil(stencil);
GLsizei framebufferWidth = 0;
GLsizei framebufferHeight = 0;
if (rectCount > 0 && rects != nullptr && GetOpenGLClearTargetExtent(view, framebufferWidth, framebufferHeight)) {
glEnable(GL_SCISSOR_TEST);
for (uint32_t i = 0; i < rectCount; ++i) {
GLint x = 0;
GLint y = 0;
GLsizei width = 0;
GLsizei height = 0;
if (!ClampOpenGLClearRect(rects[i], framebufferWidth, framebufferHeight, x, y, width, height)) {
continue;
}
glScissor(x, y, width, height);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
} else {
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, prevFBO);
(void)stencil;
glClearDepth(prevDepthClear);
glClearStencil(prevStencilClear);
glDepthMask(prevDepthMask);
glStencilMaskSeparate(GL_FRONT, static_cast<GLuint>(prevStencilMaskFront));
glStencilMaskSeparate(GL_BACK, static_cast<GLuint>(prevStencilMaskBack));
glScissor(prevScissorBox[0], prevScissorBox[1], prevScissorBox[2], prevScissorBox[3]);
if (prevScissorEnabled == GL_TRUE) {
glEnable(GL_SCISSOR_TEST);
} else {
glDisable(GL_SCISSOR_TEST);
}
}
void OpenGLCommandList::SetPipelineState(RHIPipelineState* pipelineState) {

View File

@@ -125,6 +125,92 @@ ResourceStates ResolvePostCopyState(ResourceStates previousState, ResourceStates
return previousState == ResourceStates::Common ? fallbackState : previousState;
}
bool ClampVulkanClearRect(const Rect& rect, uint32_t width, uint32_t height, VkClearRect& clearRect) {
const int32_t clampedLeft = std::clamp(rect.left, 0, static_cast<int32_t>(width));
const int32_t clampedTop = std::clamp(rect.top, 0, static_cast<int32_t>(height));
const int32_t clampedRight = std::clamp(rect.right, 0, static_cast<int32_t>(width));
const int32_t clampedBottom = std::clamp(rect.bottom, 0, static_cast<int32_t>(height));
if (clampedRight <= clampedLeft || clampedBottom <= clampedTop) {
return false;
}
clearRect.baseArrayLayer = 0;
clearRect.layerCount = 1;
clearRect.rect.offset = { clampedLeft, clampedTop };
clearRect.rect.extent = {
static_cast<uint32_t>(clampedRight - clampedLeft),
static_cast<uint32_t>(clampedBottom - clampedTop)
};
return clearRect.rect.extent.width > 0 && clearRect.rect.extent.height > 0;
}
VkRenderPass CreateTransientClearRenderPass(
VkDevice device,
bool hasColorAttachment,
Format colorFormat,
bool hasDepthAttachment,
Format depthFormat) {
std::vector<VkAttachmentDescription> attachments;
attachments.reserve((hasColorAttachment ? 1u : 0u) + (hasDepthAttachment ? 1u : 0u));
VkAttachmentReference colorAttachmentRef = {};
if (hasColorAttachment) {
VkAttachmentDescription colorAttachment = {};
colorAttachment.format = ToVulkanFormat(colorFormat);
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments.push_back(colorAttachment);
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
VkAttachmentReference depthAttachmentRef = {};
if (hasDepthAttachment) {
VkAttachmentDescription depthAttachment = {};
depthAttachment.format = ToVulkanFormat(depthFormat);
depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
depthAttachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachments.push_back(depthAttachment);
depthAttachmentRef.attachment = hasColorAttachment ? 1u : 0u;
depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
}
VkSubpassDescription subpass = {};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
if (hasColorAttachment) {
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
}
if (hasDepthAttachment) {
subpass.pDepthStencilAttachment = &depthAttachmentRef;
}
VkRenderPassCreateInfo renderPassInfo = {};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
renderPassInfo.pAttachments = attachments.data();
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
VkRenderPass renderPass = VK_NULL_HANDLE;
if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
return VK_NULL_HANDLE;
}
return renderPass;
}
void TransitionBuffer(VkCommandBuffer commandBuffer, VulkanBuffer* buffer, ResourceStates newState) {
if (commandBuffer == VK_NULL_HANDLE || buffer == nullptr || buffer->GetBuffer() == VK_NULL_HANDLE) {
return;
@@ -637,42 +723,191 @@ void VulkanCommandList::Clear(float r, float g, float b, float a, uint32_t buffe
}
}
void VulkanCommandList::ClearRenderTarget(RHIResourceView* renderTarget, const float color[4]) {
void VulkanCommandList::ClearRenderTarget(RHIResourceView* renderTarget, const float color[4], uint32_t rectCount, const Rect* rects) {
m_currentColorTarget = renderTarget;
Clear(color[0], color[1], color[2], color[3], 1);
auto* colorView = static_cast<VulkanResourceView*>(renderTarget);
if (rectCount == 0 || rects == nullptr || colorView == nullptr || colorView->GetTexture() == nullptr) {
Clear(color[0], color[1], color[2], color[3], 1);
return;
}
EndActiveRenderPass();
VulkanTexture* colorTexture = colorView->GetTexture();
TransitionTexture(colorTexture, ResourceStates::RenderTarget);
std::vector<VkClearRect> clearRects;
clearRects.reserve(rectCount);
for (uint32_t i = 0; i < rectCount; ++i) {
VkClearRect clearRect = {};
if (ClampVulkanClearRect(rects[i], colorTexture->GetWidth(), colorTexture->GetHeight(), clearRect)) {
clearRects.push_back(clearRect);
}
}
if (clearRects.empty()) {
return;
}
VkRenderPass renderPass = CreateTransientClearRenderPass(
m_device->GetDevice(),
true,
colorTexture->GetFormat(),
false,
Format::Unknown);
if (renderPass == VK_NULL_HANDLE) {
return;
}
const VkImageView attachments[] = { colorView->GetImageView() };
VkFramebufferCreateInfo framebufferInfo = {};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = renderPass;
framebufferInfo.attachmentCount = 1;
framebufferInfo.pAttachments = attachments;
framebufferInfo.width = colorTexture->GetWidth();
framebufferInfo.height = colorTexture->GetHeight();
framebufferInfo.layers = 1;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
if (vkCreateFramebuffer(m_device->GetDevice(), &framebufferInfo, nullptr, &framebuffer) != VK_SUCCESS) {
vkDestroyRenderPass(m_device->GetDevice(), renderPass, nullptr);
return;
}
VkRenderPassBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
beginInfo.renderPass = renderPass;
beginInfo.framebuffer = framebuffer;
beginInfo.renderArea.offset = { 0, 0 };
beginInfo.renderArea.extent = { colorTexture->GetWidth(), colorTexture->GetHeight() };
beginInfo.clearValueCount = 0;
beginInfo.pClearValues = nullptr;
vkCmdBeginRenderPass(m_commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkClearAttachment attachment = {};
attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
attachment.colorAttachment = 0;
attachment.clearValue.color.float32[0] = color[0];
attachment.clearValue.color.float32[1] = color[1];
attachment.clearValue.color.float32[2] = color[2];
attachment.clearValue.color.float32[3] = color[3];
vkCmdClearAttachments(
m_commandBuffer,
1,
&attachment,
static_cast<uint32_t>(clearRects.size()),
clearRects.data());
vkCmdEndRenderPass(m_commandBuffer);
vkDestroyFramebuffer(m_device->GetDevice(), framebuffer, nullptr);
vkDestroyRenderPass(m_device->GetDevice(), renderPass, nullptr);
}
void VulkanCommandList::ClearDepthStencil(RHIResourceView* depthStencil, float depth, uint8_t stencil) {
void VulkanCommandList::ClearDepthStencil(RHIResourceView* depthStencil, float depth, uint8_t stencil, uint32_t rectCount, const Rect* rects) {
auto* depthView = static_cast<VulkanResourceView*>(depthStencil != nullptr ? depthStencil : m_currentDepthTarget);
if (depthView == nullptr || depthView->GetTexture() == nullptr) {
return;
}
if (rectCount == 0 || rects == nullptr) {
EndActiveRenderPass();
VulkanTexture* texture = depthView->GetTexture();
TransitionTexture(texture, ResourceStates::CopyDst);
VkClearDepthStencilValue clearValue = {};
clearValue.depth = depth;
clearValue.stencil = stencil;
VkImageSubresourceRange range = {};
range.aspectMask = GetImageAspectMask(texture->GetFormat());
range.baseMipLevel = 0;
range.levelCount = 1;
range.baseArrayLayer = 0;
range.layerCount = 1;
vkCmdClearDepthStencilImage(
m_commandBuffer,
texture->GetImage(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
&clearValue,
1,
&range);
TransitionTexture(texture, ResourceStates::DepthWrite);
return;
}
EndActiveRenderPass();
VulkanTexture* texture = depthView->GetTexture();
TransitionTexture(texture, ResourceStates::CopyDst);
VkClearDepthStencilValue clearValue = {};
clearValue.depth = depth;
clearValue.stencil = stencil;
VkImageSubresourceRange range = {};
range.aspectMask = GetImageAspectMask(texture->GetFormat());
range.baseMipLevel = 0;
range.levelCount = 1;
range.baseArrayLayer = 0;
range.layerCount = 1;
vkCmdClearDepthStencilImage(
m_commandBuffer,
texture->GetImage(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
&clearValue,
1,
&range);
TransitionTexture(texture, ResourceStates::DepthWrite);
std::vector<VkClearRect> clearRects;
clearRects.reserve(rectCount);
for (uint32_t i = 0; i < rectCount; ++i) {
VkClearRect clearRect = {};
if (ClampVulkanClearRect(rects[i], texture->GetWidth(), texture->GetHeight(), clearRect)) {
clearRects.push_back(clearRect);
}
}
if (clearRects.empty()) {
return;
}
VkRenderPass renderPass = CreateTransientClearRenderPass(
m_device->GetDevice(),
false,
Format::Unknown,
true,
texture->GetFormat());
if (renderPass == VK_NULL_HANDLE) {
return;
}
const VkImageView attachments[] = { depthView->GetImageView() };
VkFramebufferCreateInfo framebufferInfo = {};
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferInfo.renderPass = renderPass;
framebufferInfo.attachmentCount = 1;
framebufferInfo.pAttachments = attachments;
framebufferInfo.width = texture->GetWidth();
framebufferInfo.height = texture->GetHeight();
framebufferInfo.layers = 1;
VkFramebuffer framebuffer = VK_NULL_HANDLE;
if (vkCreateFramebuffer(m_device->GetDevice(), &framebufferInfo, nullptr, &framebuffer) != VK_SUCCESS) {
vkDestroyRenderPass(m_device->GetDevice(), renderPass, nullptr);
return;
}
VkRenderPassBeginInfo beginInfo = {};
beginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
beginInfo.renderPass = renderPass;
beginInfo.framebuffer = framebuffer;
beginInfo.renderArea.offset = { 0, 0 };
beginInfo.renderArea.extent = { texture->GetWidth(), texture->GetHeight() };
beginInfo.clearValueCount = 0;
beginInfo.pClearValues = nullptr;
vkCmdBeginRenderPass(m_commandBuffer, &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkClearAttachment attachment = {};
attachment.aspectMask = GetImageAspectMask(texture->GetFormat());
attachment.clearValue.depthStencil.depth = depth;
attachment.clearValue.depthStencil.stencil = stencil;
vkCmdClearAttachments(
m_commandBuffer,
1,
&attachment,
static_cast<uint32_t>(clearRects.size()),
clearRects.data());
vkCmdEndRenderPass(m_commandBuffer);
vkDestroyFramebuffer(m_device->GetDevice(), framebuffer, nullptr);
vkDestroyRenderPass(m_device->GetDevice(), renderPass, nullptr);
}
void VulkanCommandList::CopyResource(RHIResourceView* dst, RHIResourceView* src) {

View File

@@ -343,6 +343,7 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p
renderArea.x + renderArea.width,
renderArea.y + renderArea.height
};
const RHI::Rect clearRects[] = { scissorRect };
commandList->SetViewport(viewport);
commandList->SetScissorRect(scissorRect);
@@ -353,13 +354,13 @@ bool BuiltinForwardPipeline::ExecuteForwardOpaquePass(const RenderPassContext& p
if (HasRenderClearFlag(sceneData.cameraData.clearFlags, RenderClearFlags::Color)) {
for (RHI::RHIResourceView* renderTarget : renderTargets) {
if (renderTarget != nullptr) {
commandList->ClearRenderTarget(renderTarget, clearValues);
commandList->ClearRenderTarget(renderTarget, clearValues, 1, clearRects);
}
}
}
if (surface.GetDepthAttachment() != nullptr &&
HasRenderClearFlag(sceneData.cameraData.clearFlags, RenderClearFlags::Depth)) {
commandList->ClearDepthStencil(surface.GetDepthAttachment(), 1.0f, 0);
commandList->ClearDepthStencil(surface.GetDepthAttachment(), 1.0f, 0, 1, clearRects);
}
commandList->SetPrimitiveTopology(RHI::PrimitiveTopology::TriangleList);

View File

@@ -309,6 +309,39 @@ TEST_P(RHITestFixture, CommandList_ClearRenderTarget_WithRealView) {
delete texture;
}
TEST_P(RHITestFixture, CommandList_ClearRenderTarget_WithRect) {
TextureDesc texDesc = {};
texDesc.width = 256;
texDesc.height = 256;
texDesc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
texDesc.textureType = static_cast<uint32_t>(TextureType::Texture2D);
RHITexture* texture = GetDevice()->CreateTexture(texDesc);
ASSERT_NE(texture, nullptr);
ResourceViewDesc viewDesc = {};
viewDesc.format = texDesc.format;
RHIResourceView* rtv = GetDevice()->CreateRenderTargetView(texture, viewDesc);
ASSERT_NE(rtv, nullptr);
float color[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
const Rect clearRect = { 64, 64, 192, 192 };
CommandListDesc cmdDesc = {};
cmdDesc.commandListType = static_cast<uint32_t>(CommandQueueType::Direct);
RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc);
ASSERT_NE(cmdList, nullptr);
cmdList->Reset();
cmdList->ClearRenderTarget(rtv, color, 1, &clearRect);
cmdList->Close();
cmdList->Shutdown();
delete cmdList;
delete rtv;
texture->Shutdown();
delete texture;
}
TEST_P(RHITestFixture, CommandList_ClearDepthStencil_WithRealView) {
TextureDesc texDesc = {};
texDesc.width = 256;
@@ -337,6 +370,36 @@ TEST_P(RHITestFixture, CommandList_ClearDepthStencil_WithRealView) {
delete texture;
}
TEST_P(RHITestFixture, CommandList_ClearDepthStencil_WithRect) {
TextureDesc texDesc = {};
texDesc.width = 256;
texDesc.height = 256;
texDesc.format = static_cast<uint32_t>(Format::D24_UNorm_S8_UInt);
texDesc.textureType = static_cast<uint32_t>(TextureType::Texture2D);
RHITexture* texture = GetDevice()->CreateTexture(texDesc);
ASSERT_NE(texture, nullptr);
RHIResourceView* dsv = GetDevice()->CreateDepthStencilView(texture, {});
ASSERT_NE(dsv, nullptr);
const Rect clearRect = { 32, 32, 224, 224 };
CommandListDesc cmdDesc = {};
cmdDesc.commandListType = static_cast<uint32_t>(CommandQueueType::Direct);
RHICommandList* cmdList = GetDevice()->CreateCommandList(cmdDesc);
ASSERT_NE(cmdList, nullptr);
cmdList->Reset();
cmdList->ClearDepthStencil(dsv, 1.0f, 0, 1, &clearRect);
cmdList->Close();
cmdList->Shutdown();
delete cmdList;
delete dsv;
texture->Shutdown();
delete texture;
}
TEST_P(RHITestFixture, CommandList_TransitionBarrier_WithRealResource) {
TextureDesc texDesc = {};
texDesc.width = 256;

File diff suppressed because one or more lines are too long

View File

@@ -294,6 +294,9 @@ void CameraStackSceneTest::BuildScene() {
overlayCamera->SetFarClipPlane(10.0f);
overlayCamera->SetStackType(CameraStackType::Overlay);
overlayCamera->SetCullingMask(1u << kOverlayLayer);
overlayCamera->SetClearMode(CameraClearMode::ColorAndDepth);
overlayCamera->SetViewportRect(XCEngine::Math::Rect(0.60f, 0.10f, 0.28f, 0.32f));
overlayCamera->SetClearColor(XCEngine::Math::Color(0.11f, 0.16f, 0.24f, 1.0f));
const Vector3 boundsMin = mBackpackMesh->GetBounds().GetMin();
const Vector3 boundsMax = mBackpackMesh->GetBounds().GetMax();
@@ -334,8 +337,8 @@ void CameraStackSceneTest::BuildScene() {
GameObject* overlayQuadObject = mScene->CreateGameObject("OverlayQuad");
overlayQuadObject->SetLayer(kOverlayLayer);
overlayQuadObject->GetTransform()->SetLocalPosition(Vector3(1.0f, 0.58f, 2.0f));
overlayQuadObject->GetTransform()->SetLocalScale(Vector3(0.35f, 0.35f, 1.0f));
overlayQuadObject->GetTransform()->SetLocalPosition(Vector3(0.0f, 0.0f, 2.0f));
overlayQuadObject->GetTransform()->SetLocalScale(Vector3(0.70f, 0.70f, 1.0f));
auto* overlayMeshFilter = overlayQuadObject->AddComponent<MeshFilterComponent>();
auto* overlayMeshRenderer = overlayQuadObject->AddComponent<MeshRendererComponent>();