/* =========================================================================== Radiant masked occlusion culling bridge =========================================================================== */ #include "gl_radiant_moc.h" #define USE_D3D 0 #define USE_AVX512 0 #include "thirdparty/MaskedOcclusionCulling/MaskedOcclusionCulling.h" #include namespace { struct radiantMOCState_t { MaskedOcclusionCulling* moc; unsigned int width; unsigned int height; bool active; qglRadiantMOCStats_t stats; }; radiantMOCState_t s_radiantMOC = {}; static unsigned int RadiantMOC_RoundUp(unsigned int value, unsigned int alignment) { return (value + alignment - 1) & ~(alignment - 1); } static radiantMOCState_t* RadiantMOC_FromContext(qglMOCContext_t context) { return reinterpret_cast(context); } } // namespace qglMOCContext_t QGL_MOC_Create() { radiantMOCState_t* context = new radiantMOCState_t; context->moc = NULL; context->width = 0; context->height = 0; context->active = false; context->stats.occluderTriangles = 0; context->stats.testedRects = 0; context->stats.occludedRects = 0; return context; } void QGL_MOC_Destroy(qglMOCContext_t context) { radiantMOCState_t* state = RadiantMOC_FromContext(context); if (state == NULL) { return; } if (state->moc != NULL) { MaskedOcclusionCulling::Destroy(state->moc); state->moc = NULL; } delete state; } bool QGL_MOC_BeginFrame(qglMOCContext_t context, int width, int height, float nearClip) { radiantMOCState_t* state = RadiantMOC_FromContext(context); if (state == NULL) { return false; } const unsigned int mocWidth = RadiantMOC_RoundUp(std::max(width, 64), 8); const unsigned int mocHeight = RadiantMOC_RoundUp(std::max(height, 64), 4); if (state->moc == NULL) { state->moc = MaskedOcclusionCulling::Create(MaskedOcclusionCulling::AVX2); } if (state->moc == NULL) { state->active = false; return false; } if (state->width != mocWidth || state->height != mocHeight) { state->moc->SetResolution(mocWidth, mocHeight); state->width = mocWidth; state->height = mocHeight; } state->moc->SetNearClipPlane(nearClip); state->moc->ClearBuffer(); state->active = true; state->stats.occluderTriangles = 0; state->stats.testedRects = 0; state->stats.occludedRects = 0; return true; } void QGL_MOC_EndFrame(qglMOCContext_t context) { radiantMOCState_t* state = RadiantMOC_FromContext(context); if (state != NULL) { state->active = false; } } bool QGL_MOC_IsActive(qglMOCContext_t context) { radiantMOCState_t* state = RadiantMOC_FromContext(context); return state != NULL && state->active && state->moc != NULL; } void QGL_MOC_RenderTriangles(qglMOCContext_t context, const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles) { radiantMOCState_t* state = RadiantMOC_FromContext(context); if (!QGL_MOC_IsActive(context) || verts == NULL || indices == NULL || numTriangles <= 0) { return; } MaskedOcclusionCulling::VertexLayout layout(sizeof(qglRadiantMOCClipVertex_t), 4, 8); state->moc->RenderTriangles(&verts[0].x, indices, numTriangles, NULL, MaskedOcclusionCulling::BACKFACE_NONE, MaskedOcclusionCulling::CLIP_PLANE_ALL, layout); state->stats.occluderTriangles += numTriangles; } bool QGL_MOC_TestTriangles(qglMOCContext_t context, const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles) { radiantMOCState_t* state = RadiantMOC_FromContext(context); if (!QGL_MOC_IsActive(context) || verts == NULL || indices == NULL || numTriangles <= 0) { return true; } MaskedOcclusionCulling::VertexLayout layout(sizeof(qglRadiantMOCClipVertex_t), 4, 8); state->stats.testedRects++; const MaskedOcclusionCulling::CullingResult result = state->moc->TestTriangles(&verts[0].x, indices, numTriangles, NULL, MaskedOcclusionCulling::BACKFACE_NONE, MaskedOcclusionCulling::CLIP_PLANE_ALL, layout); if (result == MaskedOcclusionCulling::OCCLUDED || result == MaskedOcclusionCulling::VIEW_CULLED) { state->stats.occludedRects++; return false; } return true; } void QGL_MOC_RenderIndexedTriangles(qglMOCContext_t context, const float* verts, const unsigned int* indices, int numTriangles, const float* modelToClipMatrix, int vertexStride, int yOffset, int zOffset) { radiantMOCState_t* state = RadiantMOC_FromContext(context); if (!QGL_MOC_IsActive(context) || verts == NULL || indices == NULL || numTriangles <= 0 || modelToClipMatrix == NULL) { return; } MaskedOcclusionCulling::VertexLayout layout(vertexStride, yOffset, zOffset); state->moc->RenderTriangles(verts, indices, numTriangles, modelToClipMatrix, MaskedOcclusionCulling::BACKFACE_NONE, MaskedOcclusionCulling::CLIP_PLANE_ALL, layout); state->stats.occluderTriangles += numTriangles; } bool QGL_MOC_TestIndexedTriangles(qglMOCContext_t context, const float* verts, const unsigned int* indices, int numTriangles, const float* modelToClipMatrix, int vertexStride, int yOffset, int zOffset) { radiantMOCState_t* state = RadiantMOC_FromContext(context); if (!QGL_MOC_IsActive(context) || verts == NULL || indices == NULL || numTriangles <= 0 || modelToClipMatrix == NULL) { return true; } MaskedOcclusionCulling::VertexLayout layout(vertexStride, yOffset, zOffset); state->stats.testedRects++; const MaskedOcclusionCulling::CullingResult result = state->moc->TestTriangles(verts, indices, numTriangles, modelToClipMatrix, MaskedOcclusionCulling::BACKFACE_NONE, MaskedOcclusionCulling::CLIP_PLANE_ALL, layout); if (result == MaskedOcclusionCulling::OCCLUDED || result == MaskedOcclusionCulling::VIEW_CULLED) { state->stats.occludedRects++; return false; } return true; } bool QGL_MOC_TestRect(qglMOCContext_t context, float xmin, float ymin, float xmax, float ymax, float wmin) { radiantMOCState_t* state = RadiantMOC_FromContext(context); if (!QGL_MOC_IsActive(context)) { return true; } state->stats.testedRects++; const MaskedOcclusionCulling::CullingResult result = state->moc->TestRect(xmin, ymin, xmax, ymax, wmin); if (result == MaskedOcclusionCulling::OCCLUDED || result == MaskedOcclusionCulling::VIEW_CULLED) { state->stats.occludedRects++; return false; } return true; } qglRadiantMOCStats_t QGL_MOC_GetStats(qglMOCContext_t context) { radiantMOCState_t* state = RadiantMOC_FromContext(context); if (state == NULL) { qglRadiantMOCStats_t emptyStats = {}; return emptyStats; } return state->stats; } bool QGL_RadiantMOC_BeginFrame(int width, int height, float nearClip) { return QGL_MOC_BeginFrame(&s_radiantMOC, width, height, nearClip); } void QGL_RadiantMOC_EndFrame() { QGL_MOC_EndFrame(&s_radiantMOC); } bool QGL_RadiantMOC_IsActive() { return QGL_MOC_IsActive(&s_radiantMOC); } void QGL_RadiantMOC_RenderTriangles(const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles) { QGL_MOC_RenderTriangles(&s_radiantMOC, verts, indices, numTriangles); } bool QGL_RadiantMOC_TestTriangles(const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles) { return QGL_MOC_TestTriangles(&s_radiantMOC, verts, indices, numTriangles); } void QGL_RadiantMOC_RenderIndexedTriangles(const float* verts, const unsigned int* indices, int numTriangles, const float* modelToClipMatrix, int vertexStride, int yOffset, int zOffset) { QGL_MOC_RenderIndexedTriangles(&s_radiantMOC, verts, indices, numTriangles, modelToClipMatrix, vertexStride, yOffset, zOffset); } bool QGL_RadiantMOC_TestIndexedTriangles(const float* verts, const unsigned int* indices, int numTriangles, const float* modelToClipMatrix, int vertexStride, int yOffset, int zOffset) { return QGL_MOC_TestIndexedTriangles(&s_radiantMOC, verts, indices, numTriangles, modelToClipMatrix, vertexStride, yOffset, zOffset); } bool QGL_RadiantMOC_TestRect(float xmin, float ymin, float xmax, float ymax, float wmin) { return QGL_MOC_TestRect(&s_radiantMOC, xmin, ymin, xmax, ymax, wmin); } qglRadiantMOCStats_t QGL_RadiantMOC_GetStats() { return s_radiantMOC.stats; }