Skip to content

Commit

Permalink
[Metal] Started implementing QueryHeap interface in Metal backend.
Browse files Browse the repository at this point in the history
- Started with MTQueryHeap implementation;
  Currently only for occlusion queries implemented as wrapper of MTLBuffer for visibility results.
- Replaced ResourceHeap in Queries example with single resource.
- Also exclude new compressed texture formats ASTC/ETC2 from Mac for now (they are available in macOS 11+).
  • Loading branch information
LukasBanana committed Aug 31, 2024
1 parent daa7814 commit 8a2e866
Show file tree
Hide file tree
Showing 16 changed files with 299 additions and 51 deletions.
3 changes: 3 additions & 0 deletions examples/Cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ if(APPLE)
"PBR/Tiles26/Tiles26_*.jpg"
"PBR/Wood13/Wood13_*.jpg"
)
add_project_resource_files(FilesExample_Queries
"Pyramid.obj"
)
add_project_resource_files(FilesExample_RenderTarget
"Crate.jpg"
)
Expand Down
2 changes: 1 addition & 1 deletion examples/Cpp/Queries/Example.450core.frag
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#version 450 core

layout(std140, binding = 0) uniform Settings
layout(std140, binding = 1) uniform Settings
{
mat4 wvpMatrix;
mat4 wMatrix;
Expand Down
Binary file modified examples/Cpp/Queries/Example.450core.frag.spv
Binary file not shown.
2 changes: 1 addition & 1 deletion examples/Cpp/Queries/Example.450core.vert
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#version 450 core

layout(std140, binding = 0) uniform Settings
layout(std140, binding = 1) uniform Settings
{
mat4 wvpMatrix;
mat4 wMatrix;
Expand Down
Binary file modified examples/Cpp/Queries/Example.450core.vert.spv
Binary file not shown.
39 changes: 25 additions & 14 deletions examples/Cpp/Queries/Example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <ExampleBase.h>
#include <chrono>
#include <thread>


class Example_Queries : public ExampleBase
Expand All @@ -18,7 +19,6 @@ class Example_Queries : public ExampleBase
LLGL::PipelineState* scenePipeline = nullptr;

LLGL::PipelineLayout* pipelineLayout = nullptr;
LLGL::ResourceHeap* resourceHeap = nullptr;

LLGL::Buffer* vertexBuffer = nullptr;
LLGL::Buffer* constantBuffer = nullptr;
Expand Down Expand Up @@ -63,7 +63,6 @@ class Example_Queries : public ExampleBase
shaderPipeline = LoadStandardShaderPipeline({ vertexFormat });
CreatePipelines();
CreateQueries();
CreateResourceHeaps();

// Show info
LLGL::Log::Printf("press SPACE KEY to enable/disable animation of occluder\n");
Expand Down Expand Up @@ -91,7 +90,7 @@ class Example_Queries : public ExampleBase
void CreatePipelines()
{
// Create pipeline layout
pipelineLayout = renderer->CreatePipelineLayout(LLGL::Parse("heap{cbuffer(0):vert:frag}"));
pipelineLayout = renderer->CreatePipelineLayout(LLGL::Parse("cbuffer(1):vert:frag"));

// Create graphics pipeline for occlusion query
LLGL::GraphicsPipelineDescriptor pipelineDesc;
Expand Down Expand Up @@ -143,45 +142,57 @@ class Example_Queries : public ExampleBase
timerQuery = renderer->CreateQueryHeap(queryDesc);
}

void CreateResourceHeaps()
{
// Create resource heap for constant buffer
resourceHeap = renderer->CreateResourceHeap(pipelineLayout, { constantBuffer });
}

std::uint64_t GetAndSyncQueryResult(LLGL::QueryHeap* query)
{
#ifdef __APPLE__
return 0; //TODO: QueryResult not implemented on macOS/iOS
#endif

// Wait until query result is available and return result
std::uint64_t result = 0;

if (query->GetType() == LLGL::QueryType::PipelineStatistics)
{
LLGL::QueryPipelineStatistics statistics;
while (!commandQueue->QueryResult(*query, 0, 1, &statistics, sizeof(statistics))) { /* wait */ }
while (!commandQueue->QueryResult(*query, 0, 1, &statistics, sizeof(statistics)))
{
// Wait and return control to other threads
std::this_thread::yield();
}
result = statistics.inputAssemblyPrimitives;
}
else
{
while (!commandQueue->QueryResult(*query, 0, 1, &result, sizeof(result))) { /* wait */ }
while (!commandQueue->QueryResult(*query, 0, 1, &result, sizeof(result)))
{
// Wait and return control to other threads
std::this_thread::yield();
}
}

return result;
}

void PrintQueryResults()
{
#ifdef __APPLE__
return; //TODO: QueryResult not implemented on macOS/iOS
#endif

// Query pipeline statistics results
LLGL::QueryPipelineStatistics stats;
while (!commandQueue->QueryResult(*geometryQuery, 0, 1, &stats, sizeof(stats)))
{
/* wait */
// Wait and return control to other threads
std::this_thread::yield();
}

// Query timing results
std::uint64_t elapsedTime = 0;
while (!commandQueue->QueryResult(*timerQuery, 0, 1, &elapsedTime, sizeof(elapsedTime)))
{
/* wait */
// Wait and return control to other threads
std::this_thread::yield();
}

// Print result
Expand Down Expand Up @@ -241,7 +252,7 @@ class Example_Queries : public ExampleBase

// Set resources
commands->SetPipelineState(*occlusionPipeline);
commands->SetResourceHeap(*resourceHeap);
commands->SetResource(0, *constantBuffer);

// Draw occluder box
SetBoxTransformAndColor(modelTransform[0], { 1, 1, 1 });
Expand Down
2 changes: 1 addition & 1 deletion examples/Cpp/Queries/Example.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

// VERTEX SHADER

cbuffer Settings : register(b0)
cbuffer Settings : register(b1)
{
float4x4 wvpMatrix;
float4x4 wMatrix;
Expand Down
53 changes: 53 additions & 0 deletions examples/Cpp/Queries/Example.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Metal shader for queries example

#include <metal_stdlib>
#include <simd/simd.h>

using namespace metal;

// VERTEX SHADER

struct InputVS
{
float3 position [[attribute(0)]];
float3 normal [[attribute(1)]];
};

struct OutputVS
{
float4 position [[position]];
float3 normal;
};

struct Scene
{
float4x4 wvpMatrix;
float4x4 wMatrix;
float4 color;
};

vertex OutputVS VS(
InputVS inp [[stage_in]],
constant Scene& scene [[buffer(1)]])
{
OutputVS outp;
outp.position = scene.wvpMatrix * float4(inp.position, 1);
outp.normal = (scene.wMatrix * float4(inp.normal, 0)).xyz;
return outp;
}


// PIXEL SHADER

fragment float4 PS(
OutputVS inp [[stage_in]],
constant Scene& scene [[buffer(1)]])
{
float3 lightDir = float3(0, 0, -1);
float NdotL = dot(lightDir, normalize(inp.normal));
float intensity = max(0.2, NdotL);
return scene.color * float4((float3)intensity, 1);
}



49 changes: 28 additions & 21 deletions sources/Renderer/Metal/Command/MTCommandContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class MTCommandContext
void SetGraphicsResourceHeap(MTResourceHeap* resourceHeap, std::uint32_t descriptorSet);
void SetBlendColor(const float blendColor[4]);
void SetStencilRef(std::uint32_t ref, const StencilFace face);
void SetVisibilityBuffer(id<MTLBuffer> buffer, MTLVisibilityResultMode mode, NSUInteger offset);

// Converts, binds, and stores the respective state in the internal compute encoder state.
void SetComputePSO(MTComputePSO* pipelineState);
Expand Down Expand Up @@ -249,6 +250,7 @@ class MTCommandContext
DirtyBit_GraphicsResourceHeap = (1 << 4),
DirtyBit_BlendColor = (1 << 5),
DirtyBit_StencilRef = (1 << 6),
DirtyBit_VisibilityResultMode = (1 << 7),

// Compute encoder
DirtyBit_ComputePSO = (1 << 0),
Expand All @@ -257,25 +259,28 @@ class MTCommandContext

struct MTRenderEncoderState
{
MTLViewport viewports[maxNumViewportsAndScissors] = {};
NSUInteger viewportCount = 0;
MTLScissorRect scissorRects[maxNumViewportsAndScissors] = {};
NSUInteger scissorRectCount = 0;
bool isScissorTestEnabled = false;
id<MTLBuffer> vertexBuffers[maxNumVertexBuffers] = {};
NSUInteger vertexBufferOffsets[maxNumVertexBuffers] = {};
NSRange vertexBufferRange = { 0, 0 };

MTGraphicsPSO* graphicsPSO = nullptr;
MTResourceHeap* graphicsResourceHeap = nullptr;
std::uint32_t graphicsResourceSet = 0;

float blendColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
bool blendColorDynamic = false;

std::uint32_t stencilFrontRef = 0;
std::uint32_t stencilBackRef = 0;
bool stencilRefDynamic = false;
MTLViewport viewports[maxNumViewportsAndScissors] = {};
NSUInteger viewportCount = 0;
MTLScissorRect scissorRects[maxNumViewportsAndScissors] = {};
NSUInteger scissorRectCount = 0;
bool isScissorTestEnabled = false;
id<MTLBuffer> vertexBuffers[maxNumVertexBuffers] = {};
NSUInteger vertexBufferOffsets[maxNumVertexBuffers] = {};
NSRange vertexBufferRange = { 0, 0 };

MTGraphicsPSO* graphicsPSO = nullptr;
MTResourceHeap* graphicsResourceHeap = nullptr;
std::uint32_t graphicsResourceSet = 0;

float blendColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
bool blendColorDynamic = false;

std::uint32_t stencilFrontRef = 0;
std::uint32_t stencilBackRef = 0;
bool stencilRefDynamic = false;

MTLVisibilityResultMode visResultMode = MTLVisibilityResultModeDisabled;
NSUInteger visResultOffset = 0;
};

struct MTComputeEncoderState
Expand Down Expand Up @@ -304,6 +309,8 @@ class MTCommandContext
NSUInteger numPatchControlPoints = 0;
NSUInteger tessFactorSize = 0;
id<MTLComputePipelineState> tessPipelineState = nil;

id<MTLBuffer> visBuffer = nil;
};

private:
Expand All @@ -325,8 +332,8 @@ class MTCommandContext
MTIntermediateBuffer tessFactorBuffer_;
const NSUInteger maxThreadgroupSizeX_ = 1;

std::uint8_t renderDirtyBits_ = 0;
std::uint8_t computeDirtyBits_ = 0;
std::uint32_t renderDirtyBits_ = 0;
std::uint32_t computeDirtyBits_ = 0;

MTSwapChain* boundSwapChain_ = nullptr;

Expand Down
57 changes: 50 additions & 7 deletions sources/Renderer/Metal/Command/MTCommandContext.mm
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@
void MTCommandContext::Reset()
{
/* Reset all dirty bits */
renderDirtyBits_ = ~0;
computeDirtyBits_ = ~0;
renderDirtyBits_ = ~0u;
computeDirtyBits_ = ~0u;
isRenderEncoderPaused_ = false;
boundSwapChain_ = nullptr;
ResetRenderEncoderState();
Expand Down Expand Up @@ -420,6 +420,38 @@ static NSUInteger GetTessFactorSizeForPatchType(const MTLPatchType patchType)
renderDirtyBits_ |= DirtyBit_StencilRef;
}

void MTCommandContext::SetVisibilityBuffer(id<MTLBuffer> buffer, MTLVisibilityResultMode mode, NSUInteger offset)
{
if (buffer != nil)
{
/* Check if a new render pass must be started with the new visibility buffer */
if (contextState_.visBuffer != buffer)
{
/* Start new render pass to bind visibility buffer */
MTLRenderPassDescriptor* renderPassDesc = CopyRenderPassDesc();
renderPassDesc.visibilityResultBuffer = buffer;
UpdateRenderPass(renderPassDesc);
[renderPassDesc release];
contextState_.visBuffer = buffer;
}

/* Check if visibility mode or offset must be updated in the render command encoder */
if (renderEncoderState_.visResultMode != mode ||
renderEncoderState_.visResultOffset != offset)
{
renderEncoderState_.visResultMode = mode;
renderEncoderState_.visResultOffset = offset;
renderDirtyBits_ |= DirtyBit_VisibilityResultMode;
}
}
else if (renderEncoderState_.visResultMode != MTLVisibilityResultModeDisabled)
{
/* Disable visibility result mode but don't bother starting a new render pass */
renderEncoderState_.visResultMode = MTLVisibilityResultModeDisabled;
renderDirtyBits_ |= DirtyBit_VisibilityResultMode;
}
}

void MTCommandContext::SetComputePSO(MTComputePSO* pipelineState)
{
if (pipelineState != nullptr && computeEncoderState_.computePSO != pipelineState)
Expand Down Expand Up @@ -625,18 +657,28 @@ static NSUInteger GetTessFactorSizeForPatchType(const MTLPatchType patchType)
else
[renderEncoder_ setStencilReferenceValue:renderEncoderState_.stencilFrontRef];
}
if (contextState_.visBuffer != nil && (renderDirtyBits_ & DirtyBit_VisibilityResultMode) != 0)
{
/* Set visibility result mode and offset */
[renderEncoder_
setVisibilityResultMode: renderEncoderState_.visResultMode
offset: renderEncoderState_.visResultOffset
];
}

/* Reset all dirty bits */
renderDirtyBits_ = 0;
}

void MTCommandContext::ResetRenderEncoderState()
{
renderEncoderState_.viewportCount = 0;
renderEncoderState_.scissorRectCount = 0;
renderEncoderState_.vertexBufferRange.length = 0;
renderEncoderState_.graphicsPSO = nullptr;
renderEncoderState_.graphicsResourceHeap = nullptr;
renderEncoderState_.viewportCount = 0;
renderEncoderState_.scissorRectCount = 0;
renderEncoderState_.vertexBufferRange.length = 0;
renderEncoderState_.graphicsPSO = nullptr;
renderEncoderState_.graphicsResourceHeap = nullptr;
renderEncoderState_.visResultMode = MTLVisibilityResultModeDisabled;
renderEncoderState_.visResultOffset = 0;
}

void MTCommandContext::SubmitComputeEncoderState()
Expand Down Expand Up @@ -674,6 +716,7 @@ static NSUInteger GetTessFactorSizeForPatchType(const MTLPatchType patchType)
contextState_.numPatchControlPoints = 0;
contextState_.tessPipelineState = nil;
contextState_.boundPipelineState = nullptr;
contextState_.visBuffer = nil;
}

NSUInteger MTCommandContext::GetMaxLocalThreads(id<MTLComputePipelineState> computePSO) const
Expand Down
Loading

0 comments on commit 8a2e866

Please sign in to comment.