mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-12 08:11:10 +02:00
Added missing files.
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Radiant masked occlusion culling bridge
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "gl_radiant_moc.h"
|
||||
|
||||
#define USE_D3D 0
|
||||
#define USE_AVX512 0
|
||||
#include "thirdparty/MaskedOcclusionCulling/MaskedOcclusionCulling.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
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<radiantMOCState_t*>(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;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Radiant masked occlusion culling bridge
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct qglRadiantMOCClipVertex_t {
|
||||
float x;
|
||||
float y;
|
||||
float w;
|
||||
};
|
||||
|
||||
struct qglRadiantMOCStats_t {
|
||||
int occluderTriangles;
|
||||
int testedRects;
|
||||
int occludedRects;
|
||||
};
|
||||
|
||||
typedef void* qglMOCContext_t;
|
||||
|
||||
qglMOCContext_t QGL_MOC_Create();
|
||||
void QGL_MOC_Destroy(qglMOCContext_t context);
|
||||
bool QGL_MOC_BeginFrame(qglMOCContext_t context, int width, int height, float nearClip);
|
||||
void QGL_MOC_EndFrame(qglMOCContext_t context);
|
||||
bool QGL_MOC_IsActive(qglMOCContext_t context);
|
||||
void QGL_MOC_RenderTriangles(qglMOCContext_t context, const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles);
|
||||
bool QGL_MOC_TestTriangles(qglMOCContext_t context, const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles);
|
||||
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);
|
||||
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);
|
||||
bool QGL_MOC_TestRect(qglMOCContext_t context, float xmin, float ymin, float xmax, float ymax, float wmin);
|
||||
qglRadiantMOCStats_t QGL_MOC_GetStats(qglMOCContext_t context);
|
||||
|
||||
bool QGL_RadiantMOC_BeginFrame(int width, int height, float nearClip);
|
||||
void QGL_RadiantMOC_EndFrame();
|
||||
bool QGL_RadiantMOC_IsActive();
|
||||
void QGL_RadiantMOC_RenderTriangles(const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles);
|
||||
bool QGL_RadiantMOC_TestTriangles(const qglRadiantMOCClipVertex_t* verts, const unsigned int* indices, int numTriangles);
|
||||
void QGL_RadiantMOC_RenderIndexedTriangles(const float* verts, const unsigned int* indices, int numTriangles, const float* modelToClipMatrix, int vertexStride, int yOffset, int zOffset);
|
||||
bool QGL_RadiantMOC_TestIndexedTriangles(const float* verts, const unsigned int* indices, int numTriangles, const float* modelToClipMatrix, int vertexStride, int yOffset, int zOffset);
|
||||
bool QGL_RadiantMOC_TestRect(float xmin, float ymin, float xmax, float ymax, float wmin);
|
||||
qglRadiantMOCStats_t QGL_RadiantMOC_GetStats();
|
||||
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
===========================================================================
|
||||
|
||||
Renderer masked occlusion culling for one-frame-late light rejection.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "tr_local.h"
|
||||
#include "../opengl/gl_radiant_moc.h"
|
||||
|
||||
#include <float.h>
|
||||
#include <windows.h>
|
||||
#include <vector>
|
||||
|
||||
struct rendererMOCLightQuery_t {
|
||||
int lightIndex;
|
||||
int lastModifiedFrameNum;
|
||||
const srfTriangles_t* tri;
|
||||
int numTriangles;
|
||||
float modelToClip[16];
|
||||
float xmin;
|
||||
float ymin;
|
||||
float xmax;
|
||||
float ymax;
|
||||
float wmin;
|
||||
};
|
||||
|
||||
struct rendererMOCIndexedMesh_t {
|
||||
const srfTriangles_t* tri;
|
||||
int numTriangles;
|
||||
float modelToClip[16];
|
||||
};
|
||||
|
||||
struct rendererMOCJob_t {
|
||||
int sequence;
|
||||
idRenderWorldLocal* world;
|
||||
int lightCount;
|
||||
int width;
|
||||
int height;
|
||||
float nearClip;
|
||||
std::vector<rendererMOCIndexedMesh_t> occluders;
|
||||
std::vector<rendererMOCLightQuery_t> lightQueries;
|
||||
};
|
||||
|
||||
struct rendererMOCResult_t {
|
||||
bool valid;
|
||||
bool consumed;
|
||||
int sequence;
|
||||
idRenderWorldLocal* world;
|
||||
std::vector<unsigned char> lightVisible;
|
||||
std::vector<int> lightModifiedFrames;
|
||||
int occluderTriangles;
|
||||
int testedLights;
|
||||
int occludedLights;
|
||||
};
|
||||
|
||||
static CRITICAL_SECTION s_rendererMOCCriticalSection;
|
||||
static HANDLE s_rendererMOCWorkEvent = NULL;
|
||||
static HANDLE s_rendererMOCThread = NULL;
|
||||
static bool s_rendererMOCInitialized = false;
|
||||
static bool s_rendererMOCShutdown = false;
|
||||
static bool s_rendererMOCHasPendingJob = false;
|
||||
static bool s_rendererMOCWorkerBusy = false;
|
||||
static bool s_rendererMOCHasCompletedResult = false;
|
||||
static int s_rendererMOCSequence = 0;
|
||||
static rendererMOCJob_t s_rendererMOCPendingJob;
|
||||
static rendererMOCResult_t s_rendererMOCCompletedResult;
|
||||
static rendererMOCResult_t s_rendererMOCLastResult;
|
||||
|
||||
static float R_MOC_ClampFloat(float value, float minValue, float maxValue) {
|
||||
if (value < minValue) {
|
||||
return minValue;
|
||||
}
|
||||
if (value > maxValue) {
|
||||
return maxValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool R_MOC_BuildModelToClipMatrix(const viewDef_t* viewDef, const float* modelMatrix, float matrix[16]) {
|
||||
const float tanX = idMath::Tan16(DEG2RAD(viewDef->renderView.fov_x * 0.5f));
|
||||
const float tanY = idMath::Tan16(DEG2RAD(viewDef->renderView.fov_y * 0.5f));
|
||||
|
||||
if (tanX <= 0.0f || tanY <= 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int column = 0; column < 3; column++) {
|
||||
idVec3 worldAxis;
|
||||
if (modelMatrix != NULL) {
|
||||
worldAxis.Set(modelMatrix[column * 4 + 0], modelMatrix[column * 4 + 1], modelMatrix[column * 4 + 2]);
|
||||
} else {
|
||||
worldAxis.Zero();
|
||||
worldAxis[column] = 1.0f;
|
||||
}
|
||||
|
||||
matrix[column * 4 + 0] = (worldAxis * viewDef->renderView.viewaxis[1]) / tanX;
|
||||
matrix[column * 4 + 1] = (worldAxis * viewDef->renderView.viewaxis[2]) / tanY;
|
||||
matrix[column * 4 + 2] = 0.0f;
|
||||
matrix[column * 4 + 3] = worldAxis * viewDef->renderView.viewaxis[0];
|
||||
}
|
||||
|
||||
idVec3 worldOrigin;
|
||||
if (modelMatrix != NULL) {
|
||||
worldOrigin.Set(modelMatrix[12], modelMatrix[13], modelMatrix[14]);
|
||||
} else {
|
||||
worldOrigin.Zero();
|
||||
}
|
||||
|
||||
const idVec3 local = worldOrigin - viewDef->renderView.vieworg;
|
||||
matrix[12] = (local * viewDef->renderView.viewaxis[1]) / tanX;
|
||||
matrix[13] = (local * viewDef->renderView.viewaxis[2]) / tanY;
|
||||
matrix[14] = 0.0f;
|
||||
matrix[15] = local * viewDef->renderView.viewaxis[0];
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool R_MOC_MaterialCanOcclude(const idMaterial* shader) {
|
||||
if (shader == NULL || !shader->IsDrawn()) {
|
||||
return false;
|
||||
}
|
||||
if (shader->Coverage() != MC_OPAQUE) {
|
||||
return false;
|
||||
}
|
||||
if (shader->HasSubview() || shader->IsSky()) {
|
||||
return false;
|
||||
}
|
||||
if (shader->GetContentFlags() & CONTENTS_AREAPORTAL) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void R_MOC_AddOccluderSurface(const viewDef_t* viewDef, const viewEntity_t* vEntity, const modelSurface_t* surface, rendererMOCJob_t& job) {
|
||||
if (surface == NULL || surface->geometry == NULL || !R_MOC_MaterialCanOcclude(surface->shader)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const srfTriangles_t* tri = surface->geometry;
|
||||
if (tri->numIndexes < 3 || tri->numVerts <= 0 || tri->indexes == NULL || tri->verts == NULL) {
|
||||
return;
|
||||
}
|
||||
if (sizeof(tri->indexes[0]) != sizeof(unsigned int)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rendererMOCIndexedMesh_t mesh;
|
||||
mesh.tri = tri;
|
||||
mesh.numTriangles = tri->numIndexes / 3;
|
||||
if (!R_MOC_BuildModelToClipMatrix(viewDef, vEntity->modelMatrix, mesh.modelToClip)) {
|
||||
return;
|
||||
}
|
||||
job.occluders.push_back(mesh);
|
||||
}
|
||||
|
||||
static void R_MOC_AddOccludersFromView(const viewDef_t* viewDef, rendererMOCJob_t& job) {
|
||||
for (const viewEntity_t* vEntity = viewDef->viewEntitys; vEntity; vEntity = vEntity->next) {
|
||||
const idRenderEntityLocal* entity = vEntity->entityDef;
|
||||
if (entity == NULL || entity->parms.hModel == NULL) {
|
||||
continue;
|
||||
}
|
||||
if (vEntity->scissorRect.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (entity->parms.hModel->IsDynamicModel() != DM_STATIC) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int numSurfaces = entity->parms.hModel->NumSurfaces();
|
||||
for (int surfaceNum = 0; surfaceNum < numSurfaces; surfaceNum++) {
|
||||
R_MOC_AddOccluderSurface(viewDef, vEntity, entity->parms.hModel->Surface(surfaceNum), job);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool R_MOC_BuildLightQuery(const viewDef_t* viewDef, const idRenderLightLocal* light, rendererMOCLightQuery_t& query) {
|
||||
if (light == NULL || light->frustumTris == NULL || light->frustumTris->numVerts <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const srfTriangles_t* tri = light->frustumTris;
|
||||
if (tri->numIndexes < 3 || tri->indexes == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (sizeof(tri->indexes[0]) != sizeof(unsigned int)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int numTriangles = tri->numIndexes / 3;
|
||||
if (numTriangles <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
query.lightIndex = light->index;
|
||||
query.lastModifiedFrameNum = light->lastModifiedFrameNum;
|
||||
query.tri = tri;
|
||||
query.numTriangles = numTriangles;
|
||||
query.xmin = -1.0f;
|
||||
query.ymin = -1.0f;
|
||||
query.xmax = 1.0f;
|
||||
query.ymax = 1.0f;
|
||||
query.wmin = r_znear.GetFloat();
|
||||
if (!R_MOC_BuildModelToClipMatrix(viewDef, NULL, query.modelToClip)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void R_MOC_AddLightQueriesFromView(const viewDef_t* viewDef, rendererMOCJob_t& job) {
|
||||
for (const viewLight_t* vLight = viewDef->viewLights; vLight; vLight = vLight->next) {
|
||||
if (vLight->viewInsideLight) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rendererMOCLightQuery_t query;
|
||||
if (R_MOC_BuildLightQuery(viewDef, vLight->lightDef, query)) {
|
||||
job.lightQueries.push_back(query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool R_MOC_BuildJob(const viewDef_t* viewDef, rendererMOCJob_t& job) {
|
||||
if (viewDef == NULL || viewDef->renderWorld == NULL) {
|
||||
return false;
|
||||
}
|
||||
if (viewDef->isSubview || viewDef->isMirror || viewDef->isXraySubview) {
|
||||
return false;
|
||||
}
|
||||
if (viewDef->renderView.width <= 0 || viewDef->renderView.height <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
idRenderWorldLocal* world = static_cast<idRenderWorldLocal*>(viewDef->renderWorld);
|
||||
const float scale = R_MOC_ClampFloat(r_mocResolutionScale.GetFloat(), 0.125f, 1.0f);
|
||||
|
||||
job.sequence = 0;
|
||||
job.world = world;
|
||||
job.lightCount = world->lightDefs.Num();
|
||||
job.width = Max(64, idMath::Ftoi(viewDef->renderView.width * scale));
|
||||
job.height = Max(64, idMath::Ftoi(viewDef->renderView.height * scale));
|
||||
job.nearClip = r_znear.GetFloat() > 0.0f ? r_znear.GetFloat() : 1.0f;
|
||||
job.occluders.clear();
|
||||
job.lightQueries.clear();
|
||||
job.occluders.reserve(4096);
|
||||
job.lightQueries.reserve(256);
|
||||
|
||||
R_MOC_AddOccludersFromView(viewDef, job);
|
||||
R_MOC_AddLightQueriesFromView(viewDef, job);
|
||||
|
||||
return job.lightCount > 0 && !job.lightQueries.empty();
|
||||
}
|
||||
|
||||
static void R_MOC_RunJob(const rendererMOCJob_t& job, rendererMOCResult_t& result, qglMOCContext_t context) {
|
||||
result.valid = true;
|
||||
result.consumed = false;
|
||||
result.sequence = job.sequence;
|
||||
result.world = job.world;
|
||||
result.lightVisible.assign(job.lightCount, 1);
|
||||
result.lightModifiedFrames.assign(job.lightCount, -1);
|
||||
result.occluderTriangles = 0;
|
||||
result.testedLights = static_cast<int>(job.lightQueries.size());
|
||||
result.occludedLights = 0;
|
||||
|
||||
if (!QGL_MOC_BeginFrame(context, job.width, job.height, job.nearClip)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < job.occluders.size(); i++) {
|
||||
const rendererMOCIndexedMesh_t& mesh = job.occluders[i];
|
||||
if (mesh.tri == NULL || mesh.tri->verts == NULL || mesh.tri->indexes == NULL || mesh.numTriangles <= 0) {
|
||||
continue;
|
||||
}
|
||||
QGL_MOC_RenderIndexedTriangles(context,
|
||||
mesh.tri->verts[0].xyz.ToFloatPtr(),
|
||||
reinterpret_cast<const unsigned int*>(mesh.tri->indexes),
|
||||
mesh.numTriangles,
|
||||
mesh.modelToClip,
|
||||
sizeof(mesh.tri->verts[0]),
|
||||
4,
|
||||
8);
|
||||
result.occluderTriangles += mesh.numTriangles;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < job.lightQueries.size(); i++) {
|
||||
const rendererMOCLightQuery_t& query = job.lightQueries[i];
|
||||
if (query.lightIndex < 0 || query.lightIndex >= static_cast<int>(result.lightVisible.size())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool visible = true;
|
||||
if (query.tri != NULL && query.tri->verts != NULL && query.tri->indexes != NULL && query.numTriangles > 0) {
|
||||
visible = QGL_MOC_TestIndexedTriangles(context,
|
||||
query.tri->verts[0].xyz.ToFloatPtr(),
|
||||
reinterpret_cast<const unsigned int*>(query.tri->indexes),
|
||||
query.numTriangles,
|
||||
query.modelToClip,
|
||||
sizeof(query.tri->verts[0]),
|
||||
4,
|
||||
8);
|
||||
} else if (query.xmin < query.xmax && query.ymin < query.ymax) {
|
||||
visible = QGL_MOC_TestRect(context, query.xmin, query.ymin, query.xmax, query.ymax, query.wmin);
|
||||
}
|
||||
result.lightVisible[query.lightIndex] = visible ? 1 : 0;
|
||||
result.lightModifiedFrames[query.lightIndex] = query.lastModifiedFrameNum;
|
||||
if (!visible) {
|
||||
result.occludedLights++;
|
||||
}
|
||||
}
|
||||
|
||||
QGL_MOC_EndFrame(context);
|
||||
}
|
||||
|
||||
static DWORD WINAPI R_MOC_ThreadProc(LPVOID) {
|
||||
qglMOCContext_t context = QGL_MOC_Create();
|
||||
|
||||
for (;;) {
|
||||
WaitForSingleObject(s_rendererMOCWorkEvent, INFINITE);
|
||||
|
||||
rendererMOCJob_t job;
|
||||
EnterCriticalSection(&s_rendererMOCCriticalSection);
|
||||
if (s_rendererMOCShutdown) {
|
||||
LeaveCriticalSection(&s_rendererMOCCriticalSection);
|
||||
break;
|
||||
}
|
||||
if (!s_rendererMOCHasPendingJob) {
|
||||
LeaveCriticalSection(&s_rendererMOCCriticalSection);
|
||||
continue;
|
||||
}
|
||||
job = s_rendererMOCPendingJob;
|
||||
s_rendererMOCPendingJob = rendererMOCJob_t();
|
||||
s_rendererMOCHasPendingJob = false;
|
||||
s_rendererMOCWorkerBusy = true;
|
||||
LeaveCriticalSection(&s_rendererMOCCriticalSection);
|
||||
|
||||
rendererMOCResult_t result;
|
||||
R_MOC_RunJob(job, result, context);
|
||||
|
||||
EnterCriticalSection(&s_rendererMOCCriticalSection);
|
||||
s_rendererMOCCompletedResult = result;
|
||||
s_rendererMOCHasCompletedResult = true;
|
||||
s_rendererMOCWorkerBusy = false;
|
||||
LeaveCriticalSection(&s_rendererMOCCriticalSection);
|
||||
}
|
||||
|
||||
QGL_MOC_Destroy(context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void R_MOC_Init() {
|
||||
if (s_rendererMOCInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeCriticalSection(&s_rendererMOCCriticalSection);
|
||||
s_rendererMOCWorkEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (s_rendererMOCWorkEvent == NULL) {
|
||||
DeleteCriticalSection(&s_rendererMOCCriticalSection);
|
||||
return;
|
||||
}
|
||||
s_rendererMOCShutdown = false;
|
||||
s_rendererMOCThread = CreateThread(NULL, 0, R_MOC_ThreadProc, NULL, 0, NULL);
|
||||
if (s_rendererMOCThread == NULL) {
|
||||
CloseHandle(s_rendererMOCWorkEvent);
|
||||
s_rendererMOCWorkEvent = NULL;
|
||||
DeleteCriticalSection(&s_rendererMOCCriticalSection);
|
||||
return;
|
||||
}
|
||||
s_rendererMOCInitialized = true;
|
||||
}
|
||||
|
||||
static void R_MOC_HarvestCompletedResult() {
|
||||
if (!s_rendererMOCInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&s_rendererMOCCriticalSection);
|
||||
if (s_rendererMOCHasCompletedResult) {
|
||||
s_rendererMOCLastResult = s_rendererMOCCompletedResult;
|
||||
s_rendererMOCCompletedResult = rendererMOCResult_t();
|
||||
s_rendererMOCHasCompletedResult = false;
|
||||
}
|
||||
LeaveCriticalSection(&s_rendererMOCCriticalSection);
|
||||
}
|
||||
|
||||
static void R_MOC_TrySubmitJob(rendererMOCJob_t job) {
|
||||
if (!s_rendererMOCInitialized || s_rendererMOCThread == NULL || s_rendererMOCWorkEvent == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&s_rendererMOCCriticalSection);
|
||||
if (!s_rendererMOCHasPendingJob && !s_rendererMOCWorkerBusy) {
|
||||
job.sequence = ++s_rendererMOCSequence;
|
||||
s_rendererMOCPendingJob = job;
|
||||
s_rendererMOCHasPendingJob = true;
|
||||
SetEvent(s_rendererMOCWorkEvent);
|
||||
}
|
||||
LeaveCriticalSection(&s_rendererMOCCriticalSection);
|
||||
}
|
||||
|
||||
static void R_MOC_PruneViewLights(viewDef_t* viewDef) {
|
||||
if (!s_rendererMOCLastResult.valid || s_rendererMOCLastResult.consumed || s_rendererMOCLastResult.world != viewDef->renderWorld) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewLight_t** link = &viewDef->viewLights;
|
||||
while (*link != NULL) {
|
||||
viewLight_t* vLight = *link;
|
||||
idRenderLightLocal* light = vLight->lightDef;
|
||||
const int lightIndex = light ? light->index : -1;
|
||||
|
||||
if (lightIndex >= 0 &&
|
||||
lightIndex < static_cast<int>(s_rendererMOCLastResult.lightVisible.size()) &&
|
||||
lightIndex < static_cast<int>(s_rendererMOCLastResult.lightModifiedFrames.size()) &&
|
||||
s_rendererMOCLastResult.lightModifiedFrames[lightIndex] == light->lastModifiedFrameNum &&
|
||||
s_rendererMOCLastResult.lightVisible[lightIndex] == 0) {
|
||||
*link = vLight->next;
|
||||
light->viewCount = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
link = &(*link)->next;
|
||||
}
|
||||
|
||||
s_rendererMOCLastResult.consumed = true;
|
||||
}
|
||||
|
||||
bool R_MaskedOcclusionCulling_LightIsVisible(const viewDef_t* viewDef, const idRenderLightLocal* light) {
|
||||
if (!r_useMaskedOcclusionCulling.GetBool() || viewDef == NULL || light == NULL) {
|
||||
return true;
|
||||
}
|
||||
if (!s_rendererMOCLastResult.valid || s_rendererMOCLastResult.world != viewDef->renderWorld) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const int lightIndex = light->index;
|
||||
if (lightIndex < 0 ||
|
||||
lightIndex >= static_cast<int>(s_rendererMOCLastResult.lightVisible.size()) ||
|
||||
lightIndex >= static_cast<int>(s_rendererMOCLastResult.lightModifiedFrames.size())) {
|
||||
return true;
|
||||
}
|
||||
if (s_rendererMOCLastResult.lightModifiedFrames[lightIndex] != light->lastModifiedFrameNum) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return s_rendererMOCLastResult.lightVisible[lightIndex] != 0;
|
||||
}
|
||||
|
||||
void R_MaskedOcclusionCulling_ProcessView(viewDef_t* viewDef) {
|
||||
if (!r_useMaskedOcclusionCulling.GetBool()) {
|
||||
return;
|
||||
}
|
||||
|
||||
R_MOC_Init();
|
||||
R_MOC_HarvestCompletedResult();
|
||||
|
||||
rendererMOCJob_t job;
|
||||
if (R_MOC_BuildJob(viewDef, job)) {
|
||||
R_MOC_TrySubmitJob(job);
|
||||
}
|
||||
|
||||
R_MOC_PruneViewLights(viewDef);
|
||||
}
|
||||
|
||||
void R_MaskedOcclusionCulling_Shutdown() {
|
||||
if (!s_rendererMOCInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&s_rendererMOCCriticalSection);
|
||||
s_rendererMOCShutdown = true;
|
||||
SetEvent(s_rendererMOCWorkEvent);
|
||||
LeaveCriticalSection(&s_rendererMOCCriticalSection);
|
||||
|
||||
if (s_rendererMOCThread != NULL) {
|
||||
WaitForSingleObject(s_rendererMOCThread, INFINITE);
|
||||
CloseHandle(s_rendererMOCThread);
|
||||
s_rendererMOCThread = NULL;
|
||||
}
|
||||
if (s_rendererMOCWorkEvent != NULL) {
|
||||
CloseHandle(s_rendererMOCWorkEvent);
|
||||
s_rendererMOCWorkEvent = NULL;
|
||||
}
|
||||
|
||||
DeleteCriticalSection(&s_rendererMOCCriticalSection);
|
||||
s_rendererMOCInitialized = false;
|
||||
s_rendererMOCPendingJob = rendererMOCJob_t();
|
||||
s_rendererMOCCompletedResult = rendererMOCResult_t();
|
||||
s_rendererMOCLastResult = rendererMOCResult_t();
|
||||
s_rendererMOCHasPendingJob = false;
|
||||
s_rendererMOCHasCompletedResult = false;
|
||||
s_rendererMOCWorkerBusy = false;
|
||||
}
|
||||
Reference in New Issue
Block a user