Metal: Occlusion query WIP.

This commit is contained in:
Branimir Karadžić 2015-11-04 21:38:49 -08:00
parent 422fcf6052
commit 653bbea439
2 changed files with 790 additions and 701 deletions

View file

@ -712,6 +712,29 @@ namespace bgfx { namespace mtl
uint8_t m_num; // number of color handles uint8_t m_num; // number of color handles
}; };
struct OcclusionQueryMTL
{
OcclusionQueryMTL()
: m_control(BX_COUNTOF(m_query) )
{
}
void postReset();
void preReset();
void begin(RenderCommandEncoder& _rce, Frame* _render, OcclusionQueryHandle _handle);
void end(RenderCommandEncoder& _rce);
void resolve(Frame* _render, bool _wait = false);
struct Query
{
OcclusionQueryHandle m_handle;
};
Buffer m_buffer;
Query m_query[BGFX_CONFIG_MAX_OCCUSION_QUERIES];
bx::RingBufferControl m_control;
};
} /* namespace metal */ } // namespace bgfx } /* namespace metal */ } // namespace bgfx
#endif // BGFX_CONFIG_RENDERER_METAL #endif // BGFX_CONFIG_RENDERER_METAL

View file

@ -348,8 +348,8 @@ namespace bgfx { namespace mtl
if (NULL != NSClassFromString(@"CAMetalLayer") ) if (NULL != NSClassFromString(@"CAMetalLayer") )
{ {
//on iOS we need the layer as CAmetalLayer
#if BX_PLATFORM_IOS #if BX_PLATFORM_IOS
{
CAMetalLayer* metalLayer = (CAMetalLayer*)g_platformData.nwh; CAMetalLayer* metalLayer = (CAMetalLayer*)g_platformData.nwh;
if (NULL == metalLayer if (NULL == metalLayer
|| ![metalLayer isKindOfClass:NSClassFromString(@"CAMetalLayer")]) || ![metalLayer isKindOfClass:NSClassFromString(@"CAMetalLayer")])
@ -357,14 +357,16 @@ namespace bgfx { namespace mtl
BX_WARN(NULL != m_device, "Unable to create Metal device. Please set platform data window to a CAMetalLayer"); BX_WARN(NULL != m_device, "Unable to create Metal device. Please set platform data window to a CAMetalLayer");
return false; return false;
} }
m_metalLayer = metalLayer;
#elif BX_PLATFORM_OSX
// create and set metalLayer
NSWindow* nsWindow = (NSWindow*)g_platformData.nwh;
m_metalLayer = metalLayer;
}
#elif BX_PLATFORM_OSX
{
NSWindow* nsWindow = (NSWindow*)g_platformData.nwh;
[nsWindow.contentView setWantsLayer:YES]; [nsWindow.contentView setWantsLayer:YES];
m_metalLayer = [CAMetalLayer layer]; m_metalLayer = [CAMetalLayer layer];
[nsWindow.contentView setLayer:m_metalLayer]; [nsWindow.contentView setLayer:m_metalLayer];
}
#endif // BX_PLATFORM_* #endif // BX_PLATFORM_*
m_device = (id<MTLDevice>)g_platformData.context; m_device = (id<MTLDevice>)g_platformData.context;
@ -401,8 +403,8 @@ namespace bgfx { namespace mtl
m_uniformBufferFragmentOffset = 0; m_uniformBufferFragmentOffset = 0;
g_caps.supported |= (0 g_caps.supported |= (0
| BGFX_CAPS_TEXTURE_COMPARE_LEQUAL
| BGFX_CAPS_TEXTURE_3D | BGFX_CAPS_TEXTURE_3D
| BGFX_CAPS_TEXTURE_COMPARE_LEQUAL
| BGFX_CAPS_INSTANCING | BGFX_CAPS_INSTANCING
| BGFX_CAPS_VERTEX_ATTRIB_HALF | BGFX_CAPS_VERTEX_ATTRIB_HALF
// | BGFX_CAPS_FRAGMENT_DEPTH // | BGFX_CAPS_FRAGMENT_DEPTH
@ -410,6 +412,9 @@ namespace bgfx { namespace mtl
| BGFX_CAPS_COMPUTE | BGFX_CAPS_COMPUTE
| BGFX_CAPS_INDEX32 | BGFX_CAPS_INDEX32
| BGFX_CAPS_DRAW_INDIRECT | BGFX_CAPS_DRAW_INDIRECT
// | BGFX_CAPS_TEXTURE_BLIT
// | BGFX_CAPS_TEXTURE_READ_BACK
| BGFX_CAPS_OCCLUSION_QUERY
); );
g_caps.maxTextureSize = 2048; //ASK: real caps width/height: 4096, but max depth(3D) size is only: 2048 g_caps.maxTextureSize = 2048; //ASK: real caps width/height: 4096, but max depth(3D) size is only: 2048
@ -483,11 +488,15 @@ namespace bgfx { namespace mtl
bx::snprintf(s_viewName[ii], BGFX_CONFIG_MAX_VIEW_NAME_RESERVED+1, "%3d ", ii); bx::snprintf(s_viewName[ii], BGFX_CONFIG_MAX_VIEW_NAME_RESERVED+1, "%3d ", ii);
} }
m_occlusionQuery.preReset();
return true; return true;
} }
void shutdown() void shutdown()
{ {
m_occlusionQuery.postReset();
for (uint32_t ii = 0; ii < BX_COUNTOF(m_shaders); ++ii) for (uint32_t ii = 0; ii < BX_COUNTOF(m_shaders); ++ii)
{ {
m_shaders[ii].destroy(); m_shaders[ii].destroy();
@ -507,9 +516,10 @@ namespace bgfx { namespace mtl
MTL_RELEASE(m_samplerDescriptor); MTL_RELEASE(m_samplerDescriptor);
MTL_RELEASE(m_backBufferDepth); MTL_RELEASE(m_backBufferDepth);
#if BX_PLATFORM_IOS if (BX_ENABLED(BX_PLATFORM_IOS) )
{
MTL_RELEASE(m_backBufferStencil); MTL_RELEASE(m_backBufferStencil);
#endif // BX_PLATFORM_* }
MTL_RELEASE(m_uniformBuffer); MTL_RELEASE(m_uniformBuffer);
MTL_RELEASE(m_commandQueue); MTL_RELEASE(m_commandQueue);
@ -930,19 +940,7 @@ namespace bgfx { namespace mtl
release(m_backBufferDepth); release(m_backBufferDepth);
} }
m_backBufferDepth = m_device.newTextureWithDescriptor(m_textureDescriptor); m_backBufferDepth = m_device.newTextureWithDescriptor(m_textureDescriptor);
#if 0
m_textureDescriptor.pixelFormat = MTLPixelFormatStencil8;
if (NULL != m_backBufferStencil)
{
release(m_backBufferStencil);
}
m_backBufferStencil = m_device.newTextureWithDescriptor(m_textureDescriptor);
#else
m_backBufferStencil = m_backBufferDepth; m_backBufferStencil = m_backBufferDepth;
#endif // 0
bx::HashMurmur2A murmur; bx::HashMurmur2A murmur;
murmur.begin(); murmur.begin();
@ -964,14 +962,12 @@ namespace bgfx { namespace mtl
void setShaderUniform(uint8_t _flags, uint32_t _loc, const void* _val, uint32_t _numRegs) void setShaderUniform(uint8_t _flags, uint32_t _loc, const void* _val, uint32_t _numRegs)
{ {
if (_flags&BGFX_UNIFORM_FRAGMENTBIT) uint32_t offset = 0 != (_flags&BGFX_UNIFORM_FRAGMENTBIT)
{ ? m_uniformBufferFragmentOffset
memcpy(&((char*)m_uniformBuffer.contents())[m_uniformBufferFragmentOffset + _loc], _val, _numRegs*16); : m_uniformBufferVertexOffset
} ;
else uint8_t* dst = (uint8_t*)m_uniformBuffer.contents();
{ memcpy(&dst[offset + _loc], _val, _numRegs*16);
memcpy(&((char*)m_uniformBuffer.contents())[m_uniformBufferVertexOffset + _loc], _val, _numRegs*16);
}
} }
void setShaderUniform4f(uint8_t _flags, uint32_t _loc, const void* _val, uint32_t _numRegs) void setShaderUniform4f(uint8_t _flags, uint32_t _loc, const void* _val, uint32_t _numRegs)
@ -1026,7 +1022,7 @@ namespace bgfx { namespace mtl
switch ( (uint32_t)type) switch ( (uint32_t)type)
{ {
case UniformType::Mat3: case UniformType::Mat3:
case UniformType::Mat3|BGFX_UNIFORM_FRAGMENTBIT: \ case UniformType::Mat3|BGFX_UNIFORM_FRAGMENTBIT:
{ {
float* value = (float*)data; float* value = (float*)data;
for (uint32_t ii = 0, count = num/3; ii < count; ++ii, loc += 3*16, value += 9) for (uint32_t ii = 0, count = num/3; ii < count; ++ii, loc += 3*16, value += 9)
@ -1066,7 +1062,7 @@ namespace bgfx { namespace mtl
} }
} }
void setFrameBuffer(mtl::RenderPassDescriptor renderPassDescriptor, FrameBufferHandle _fbh, bool _msaa = true) void setFrameBuffer(RenderPassDescriptor renderPassDescriptor, FrameBufferHandle _fbh, bool _msaa = true)
{ {
if (!isValid(_fbh) ) if (!isValid(_fbh) )
{ {
@ -1086,7 +1082,7 @@ namespace bgfx { namespace mtl
renderPassDescriptor.colorAttachments[ii].texture = texture.m_ptr; renderPassDescriptor.colorAttachments[ii].texture = texture.m_ptr;
} }
if (isValid(frameBuffer.m_depthHandle)) if (isValid(frameBuffer.m_depthHandle) )
{ {
const TextureMtl& texture = m_textures[frameBuffer.m_depthHandle.idx]; const TextureMtl& texture = m_textures[frameBuffer.m_depthHandle.idx];
renderPassDescriptor.depthAttachment.texture = texture.m_ptr; renderPassDescriptor.depthAttachment.texture = texture.m_ptr;
@ -1197,6 +1193,12 @@ namespace bgfx { namespace mtl
return sampler; return sampler;
} }
bool isVisible(Frame* _render, OcclusionQueryHandle _handle, bool _visible)
{
m_occlusionQuery.resolve(_render);
return _visible == (0 != _render->m_occlusion[_handle.idx]);
}
uint32_t getBufferWidth() uint32_t getBufferWidth()
{ {
return m_backBufferDepth.width(); return m_backBufferDepth.width();
@ -1215,6 +1217,8 @@ namespace bgfx { namespace mtl
uint32_t m_backBufferPixelFormatHash; uint32_t m_backBufferPixelFormatHash;
uint32_t m_maxAnisotropy; uint32_t m_maxAnisotropy;
OcclusionQueryMTL m_occlusionQuery;
Buffer m_uniformBuffer; //todo: use a pool of this Buffer m_uniformBuffer; //todo: use a pool of this
uint32_t m_uniformBufferVertexOffset; uint32_t m_uniformBufferVertexOffset;
uint32_t m_uniformBufferFragmentOffset; uint32_t m_uniformBufferFragmentOffset;
@ -1255,7 +1259,7 @@ namespace bgfx { namespace mtl
id <CAMetalDrawable> m_drawable; id <CAMetalDrawable> m_drawable;
CommandBuffer m_commandBuffer; CommandBuffer m_commandBuffer;
RenderCommandEncoder m_renderCommandEncoder; RenderCommandEncoder m_renderCommandEncoder;
}; };
static RendererContextMtl* s_renderMtl; static RendererContextMtl* s_renderMtl;
@ -2102,6 +2106,48 @@ namespace bgfx { namespace mtl
return denseIdx; return denseIdx;
} }
void OcclusionQueryMTL::postReset()
{
MTL_RELEASE(m_buffer);
}
void OcclusionQueryMTL::preReset()
{
m_buffer = s_renderMtl->m_device.newBufferWithLength(BX_COUNTOF(m_query)*8, 0);
}
void OcclusionQueryMTL::begin(RenderCommandEncoder& _rce, Frame* _render, OcclusionQueryHandle _handle)
{
while (0 == m_control.reserve(1) )
{
resolve(_render, true);
}
Query& query = m_query[m_control.m_current];
query.m_handle = _handle;
_rce.setVisibilityResultMode(MTLVisibilityResultModeBoolean, _handle.idx);
}
void OcclusionQueryMTL::end(RenderCommandEncoder& _rce)
{
Query& query = m_query[m_control.m_current];
_rce.setVisibilityResultMode(MTLVisibilityResultModeDisabled, query.m_handle.idx);
m_control.commit(1);
}
void OcclusionQueryMTL::resolve(Frame* _render, bool _wait)
{
BX_UNUSED(_wait);
while (0 != m_control.available() )
{
Query& query = m_query[m_control.m_read];
uint64_t result = ( (uint64_t*)m_buffer.contents() )[query.m_handle.idx];
_render->m_occlusion[query.m_handle.idx] = 0 < result;
m_control.consume(1);
}
}
void RendererContextMtl::submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) BX_OVERRIDE void RendererContextMtl::submit(Frame* _render, ClearQuad& _clearQuad, TextVideoMemBlitter& _textVideoMemBlitter) BX_OVERRIDE
{ {
BX_UNUSED(_clearQuad); BX_UNUSED(_clearQuad);
@ -2179,7 +2225,7 @@ namespace bgfx { namespace mtl
PrimInfo prim = s_primInfo[primIndex]; PrimInfo prim = s_primInfo[primIndex];
ProgramMtl* currentProgram = NULL; ProgramMtl* currentProgram = NULL;
mtl::RenderCommandEncoder rce; RenderCommandEncoder rce;
bool wasCompute = false; bool wasCompute = false;
bool viewHasScissor = false; bool viewHasScissor = false;
@ -2193,6 +2239,8 @@ namespace bgfx { namespace mtl
uint32_t statsNumIndices = 0; uint32_t statsNumIndices = 0;
uint32_t statsKeyType[2] = {}; uint32_t statsKeyType[2] = {};
m_occlusionQuery.resolve(_render);
if (0 == (_render->m_debug&BGFX_DEBUG_IFH) ) if (0 == (_render->m_debug&BGFX_DEBUG_IFH) )
{ {
bool viewRestart = false; bool viewRestart = false;
@ -2258,7 +2306,8 @@ namespace bgfx { namespace mtl
viewScissorRect = viewHasScissor ? scissorRect : viewState.m_rect; viewScissorRect = viewHasScissor ? scissorRect : viewState.m_rect;
Clear& clr = _render->m_clear[view]; Clear& clr = _render->m_clear[view];
mtl::RenderPassDescriptor renderPassDescriptor = newRenderPassDescriptor(); RenderPassDescriptor renderPassDescriptor = newRenderPassDescriptor();
renderPassDescriptor.visibilityResultBuffer = m_occlusionQuery.m_buffer;
//todo: check FB size //todo: check FB size
uint32_t width = getBufferWidth(); uint32_t width = getBufferWidth();
@ -2370,6 +2419,14 @@ namespace bgfx { namespace mtl
const RenderDraw& draw = renderItem.draw; const RenderDraw& draw = renderItem.draw;
const bool hasOcclusionQuery = 0 != (draw.m_stateFlags & BGFX_STATE_INTERNAL_OCCLUSION_QUERY);
if (isValid(draw.m_occlusionQuery)
&& !hasOcclusionQuery
&& !isVisible(_render, draw.m_occlusionQuery, 0 != (draw.m_submitFlags&BGFX_SUBMIT_INTERNAL_OCCLUSION_VISIBLE) ) )
{
continue;
}
const uint64_t newFlags = draw.m_stateFlags; const uint64_t newFlags = draw.m_stateFlags;
uint64_t changedFlags = currentState.m_stateFlags ^ draw.m_stateFlags; uint64_t changedFlags = currentState.m_stateFlags ^ draw.m_stateFlags;
currentState.m_stateFlags = newFlags; currentState.m_stateFlags = newFlags;
@ -2484,12 +2541,12 @@ namespace bgfx { namespace mtl
bool constantsChanged = draw.m_constBegin < draw.m_constEnd; bool constantsChanged = draw.m_constBegin < draw.m_constEnd;
rendererUpdateUniforms(this, _render->m_uniformBuffer, draw.m_constBegin, draw.m_constEnd); rendererUpdateUniforms(this, _render->m_uniformBuffer, draw.m_constBegin, draw.m_constEnd);
if (key.m_program != programIdx || if (key.m_program != programIdx
(BGFX_STATE_BLEND_MASK|BGFX_STATE_BLEND_EQUATION_MASK|BGFX_STATE_ALPHA_WRITE|BGFX_STATE_RGB_WRITE|BGFX_STATE_BLEND_INDEPENDENT|BGFX_STATE_MSAA) & changedFlags || || (BGFX_STATE_BLEND_MASK|BGFX_STATE_BLEND_EQUATION_MASK|BGFX_STATE_ALPHA_WRITE|BGFX_STATE_RGB_WRITE|BGFX_STATE_BLEND_INDEPENDENT|BGFX_STATE_MSAA) & changedFlags
currentState.m_vertexBuffer.idx != draw.m_vertexBuffer.idx || || currentState.m_vertexBuffer.idx != draw.m_vertexBuffer.idx
currentState.m_vertexDecl.idx != draw.m_vertexDecl.idx || || currentState.m_vertexDecl.idx != draw.m_vertexDecl.idx
currentState.m_instanceDataStride != draw.m_instanceDataStride || || currentState.m_instanceDataStride != draw.m_instanceDataStride
( (blendFactor != draw.m_rgba) && !!(newFlags & BGFX_STATE_BLEND_INDEPENDENT) ) ) || ( (blendFactor != draw.m_rgba) && !!(newFlags & BGFX_STATE_BLEND_INDEPENDENT) ) )
{ {
programIdx = key.m_program; programIdx = key.m_program;
currentState.m_vertexDecl = draw.m_vertexDecl; currentState.m_vertexDecl = draw.m_vertexDecl;
@ -2532,14 +2589,14 @@ namespace bgfx { namespace mtl
uint32_t vertexUniformBufferSize = program.m_vshConstantBufferSize; uint32_t vertexUniformBufferSize = program.m_vshConstantBufferSize;
uint32_t fragmentUniformBufferSize = program.m_fshConstantBufferSize; uint32_t fragmentUniformBufferSize = program.m_fshConstantBufferSize;
if (vertexUniformBufferSize ) if (vertexUniformBufferSize)
{ {
m_uniformBufferVertexOffset = BX_ALIGN_MASK(m_uniformBufferVertexOffset, program.m_vshConstantBufferAlignmentMask); m_uniformBufferVertexOffset = BX_ALIGN_MASK(m_uniformBufferVertexOffset, program.m_vshConstantBufferAlignmentMask);
rce.setVertexBuffer(m_uniformBuffer, m_uniformBufferVertexOffset, 0); rce.setVertexBuffer(m_uniformBuffer, m_uniformBufferVertexOffset, 0);
} }
m_uniformBufferFragmentOffset = m_uniformBufferVertexOffset + vertexUniformBufferSize; m_uniformBufferFragmentOffset = m_uniformBufferVertexOffset + vertexUniformBufferSize;
if (fragmentUniformBufferSize ) if (fragmentUniformBufferSize)
{ {
m_uniformBufferFragmentOffset = BX_ALIGN_MASK(m_uniformBufferFragmentOffset, program.m_fshConstantBufferAlignmentMask); m_uniformBufferFragmentOffset = BX_ALIGN_MASK(m_uniformBufferFragmentOffset, program.m_fshConstantBufferAlignmentMask);
rce.setFragmentBuffer(m_uniformBuffer, m_uniformBufferFragmentOffset, 0); rce.setFragmentBuffer(m_uniformBuffer, m_uniformBufferFragmentOffset, 0);
@ -2591,8 +2648,7 @@ namespace bgfx { namespace mtl
if (currentState.m_vertexBuffer.idx != draw.m_vertexBuffer.idx if (currentState.m_vertexBuffer.idx != draw.m_vertexBuffer.idx
|| currentState.m_startVertex != draw.m_startVertex || currentState.m_startVertex != draw.m_startVertex
|| currentState.m_instanceDataBuffer.idx != draw.m_instanceDataBuffer.idx || currentState.m_instanceDataBuffer.idx != draw.m_instanceDataBuffer.idx
|| currentState.m_instanceDataOffset != draw.m_instanceDataOffset || currentState.m_instanceDataOffset != draw.m_instanceDataOffset)
)
{ {
currentState.m_vertexBuffer = draw.m_vertexBuffer; currentState.m_vertexBuffer = draw.m_vertexBuffer;
currentState.m_startVertex = draw.m_startVertex; currentState.m_startVertex = draw.m_startVertex;
@ -2635,6 +2691,11 @@ namespace bgfx { namespace mtl
uint32_t numPrimsRendered = 0; uint32_t numPrimsRendered = 0;
uint32_t numDrawIndirect = 0; uint32_t numDrawIndirect = 0;
if (hasOcclusionQuery)
{
m_occlusionQuery.begin(rce, _render, draw.m_occlusionQuery);
}
if (isValid(draw.m_indirectBuffer) ) if (isValid(draw.m_indirectBuffer) )
{ {
// TODO: indirect draw // TODO: indirect draw
@ -2677,6 +2738,11 @@ namespace bgfx { namespace mtl
} }
} }
if (hasOcclusionQuery)
{
m_occlusionQuery.end(rce);
}
statsNumPrimsSubmitted[primIndex] += numPrimsSubmitted; statsNumPrimsSubmitted[primIndex] += numPrimsSubmitted;
statsNumPrimsRendered[primIndex] += numPrimsRendered; statsNumPrimsRendered[primIndex] += numPrimsRendered;
statsNumInstances[primIndex] += numInstances; statsNumInstances[primIndex] += numInstances;