Optimize render encoder end/start

This commit is contained in:
David Chavez 2024-12-21 08:10:42 +01:00
parent 49929ab728
commit 9efb1ab743
5 changed files with 80 additions and 23 deletions

View File

@ -1075,7 +1075,7 @@ namespace RT64 {
ctx.commandList->setGraphicsPushConstants(0, &pushConstant1);
drawRasterTriangle(ctx);
// Draw second triangle with push constants for red color
// Draw third triangle with push constants for green color
offsetViewport.y -= 100.0f;
ctx.commandList->setViewports(offsetViewport);
RasterPushConstant pushConstant2;
@ -1416,7 +1416,7 @@ namespace RT64 {
using TestSetupFunc = std::function<std::unique_ptr<TestBase>()>;
static std::vector<TestSetupFunc> g_Tests;
static std::unique_ptr<TestBase> g_CurrentTest;
static uint32_t g_CurrentTestIndex = 2;
static uint32_t g_CurrentTestIndex = 1;
void RegisterTests() {
g_Tests.push_back([]() { return std::make_unique<ClearTest>(); });

View File

@ -90,6 +90,14 @@ struct SamplePosition
float x;
float y;
bool operator==(const SamplePosition& other) const {
return x == other.x && y == other.y;
}
bool operator!=(const SamplePosition& other) const {
return !(*this == other);
}
} _MTL_PACKED;
struct ResourceID

View File

@ -536,7 +536,6 @@ namespace RT64 {
state->winding = MTL::WindingClockwise;
state->sampleCount = desc.multisampling.sampleCount;
if (desc.multisampling.sampleCount > 1) {
state->samplePositions = new MTL::SamplePosition[desc.multisampling.sampleCount];
for (uint32_t i = 0; i < desc.multisampling.sampleCount; i++) {
state->samplePositions[i] = { (float)desc.multisampling.sampleLocations[i].x, (float)desc.multisampling.sampleLocations[i].y };
}
@ -562,8 +561,6 @@ namespace RT64 {
MetalGraphicsPipeline::~MetalGraphicsPipeline() {
state->renderPipelineState->release();
state->depthStencilState->release();
// TODO: better way to dispose of sample positions
delete[] state->samplePositions;
delete state;
}
@ -1195,8 +1192,15 @@ namespace RT64 {
case MetalPipeline::Type::Graphics: {
const auto *graphicsPipeline = static_cast<const MetalGraphicsPipeline *>(interfacePipeline);
if (activeRenderState) {
if (activeRenderState->samplePositions != graphicsPipeline->state->samplePositions || activeRenderState->sampleCount != graphicsPipeline->state->sampleCount) {
if (activeRenderState->sampleCount != graphicsPipeline->state->sampleCount) {
endActiveRenderEncoder();
} else if (activeRenderState->sampleCount > 1) {
for (uint32_t i = 0; i < activeRenderState->sampleCount; i++) {
if (activeRenderState->samplePositions[i] != graphicsPipeline->state->samplePositions[i]) {
endActiveRenderEncoder();
break;
}
}
}
}
@ -1400,17 +1404,23 @@ namespace RT64 {
}
void MetalCommandList::setFramebuffer(const RenderFramebuffer *framebuffer) {
// If we're changing framebuffers, we need to end current encoder and reset state
if (targetFramebuffer != framebuffer) {
endOtherEncoders(EncoderType::Render);
endActiveRenderEncoder();
targetFramebuffer = static_cast<const MetalFramebuffer*>(framebuffer);
// Mark all state as needing update with the new encoder
if (targetFramebuffer != nullptr) {
dirtyGraphicsState.setAll();
endOtherEncoders(EncoderType::Render);
if (framebuffer != nullptr) {
auto incomingFramebuffer = static_cast<const MetalFramebuffer*>(framebuffer);
// check if we need to end the current encoder
if (targetFramebuffer == nullptr || *targetFramebuffer != *incomingFramebuffer) {
endActiveRenderEncoder();
targetFramebuffer = incomingFramebuffer;
// Mark all state as needing update with the new encoder
if (targetFramebuffer != nullptr) {
dirtyGraphicsState.setAll();
}
}
} else {
targetFramebuffer = nullptr;
}
}

View File

@ -18,7 +18,6 @@ namespace RT64 {
struct MetalGraphicsPipeline;
struct MetalPool;
struct MetalDrawable;
struct ExtendedRenderTexture;
enum class EncoderType {
Render,
@ -92,7 +91,7 @@ namespace RT64 {
MTL::CullMode cullMode = MTL::CullModeNone;
MTL::DepthClipMode depthClipMode = MTL::DepthClipModeClip;
MTL::Winding winding = MTL::WindingClockwise;
MTL::SamplePosition *samplePositions = nullptr;
MTL::SamplePosition samplePositions[16] = {};
uint32_t sampleCount = 0;
};
@ -104,6 +103,11 @@ namespace RT64 {
: buffer(buffer), offset(offset) {}
};
struct ExtendedRenderTexture: RenderTexture {
RenderTextureDesc desc;
virtual MTL::Texture* getTexture() const = 0;
};
struct MetalDescriptorSet : RenderDescriptorSet {
std::unordered_map<uint32_t, MTL::Texture *> indicesToTextures;
std::unordered_map<uint32_t, MetalBufferBinding> indicesToBuffers;
@ -164,6 +168,38 @@ namespace RT64 {
~MetalFramebuffer() override;
uint32_t getWidth() const override;
uint32_t getHeight() const override;
// this comparison is tailored towards whether we'll require a new encoder
bool operator==(const MetalFramebuffer& other) const {
if (colorAttachments.size() != other.colorAttachments.size()) {
return false;
}
for (size_t i = 0; i < colorAttachments.size(); i++) {
if (colorAttachments[i]->getTexture() != other.colorAttachments[i]->getTexture() ||
colorAttachments[i]->desc.multisampling.sampleCount != other.colorAttachments[i]->desc.multisampling.sampleCount) {
return false;
}
// Compare individual sample locations if multisampling is enabled
if (colorAttachments[i]->desc.multisampling.sampleCount > 1) {
for (uint32_t s = 0; s < colorAttachments[i]->desc.multisampling.sampleCount; s++) {
const auto& loc1 = colorAttachments[i]->desc.multisampling.sampleLocations[s];
const auto& loc2 = other.colorAttachments[i]->desc.multisampling.sampleLocations[s];
if (loc1 != loc2) {
return false;
}
}
}
}
return depthAttachment == other.depthAttachment;
}
bool operator!=(const MetalFramebuffer& other) const {
return !(*this == other);
}
};
struct MetalCommandList : RenderCommandList {
@ -358,11 +394,6 @@ namespace RT64 {
~MetalBufferFormattedView() override;
};
struct ExtendedRenderTexture: RenderTexture {
RenderTextureDesc desc;
virtual MTL::Texture* getTexture() const = 0;
};
struct MetalDrawable : ExtendedRenderTexture {
CA::MetalDrawable *mtl = nullptr;

View File

@ -696,6 +696,14 @@ namespace RT64 {
// Valid range is [-8, 7].
int8_t x = 0;
int8_t y = 0;
bool operator==(const RenderMultisamplingLocation& other) const {
return x == other.x && y == other.y;
}
bool operator!=(const RenderMultisamplingLocation& other) const {
return !(*this == other);
}
};
struct RenderMultisampling {