Compare commits

...

14 Commits

Author SHA1 Message Date
e7ebe1e243 Update dqn lib 2017-06-24 15:33:18 +10:00
54c6abd9d7 Update dqn with CPP api for memstacks 2017-06-23 19:03:36 +10:00
26e6892d64 Fix some dqn platform compile problems 2017-06-20 22:22:39 +10:00
08b2832436 Fix minor bugs in dqn 2017-06-20 19:36:58 +10:00
e1545c7977 Update DQN with work queue and minor changes 2017-06-20 18:37:35 +10:00
eeb773747a Improve assert with variadic macro for user msg 2017-06-20 15:31:44 +10:00
5397cdd9b9 Better assert(), move some Win32 functions to DQN
Asserts are now more defensive and diagnostic. Initially asserts provide a hard
break in the program, and the intention is to disable asserts for release.
Having experienced bugs in release mode due to optimisations with asserts off
there's little protection against errors that occur in release mode since all
asserts are off.

Now asserts can be used in release mode whilst still evaluating the expression,
and allowing user messages/diagnostics to console.
2017-06-20 02:13:03 +10:00
e860145e77 Lock pixels for multithread more granularly level 2017-06-19 18:22:02 +10:00
e660281211 Fix multithread bug causing invalid ptr references
Mesh rendering was not waiting until all jobs were complete before moving on
causing longer jobs to use old pointer references once the next frame started
rendering.
2017-06-19 14:14:13 +10:00
630522f8a3 Start multithreading mesh render 2017-06-18 23:07:49 +10:00
079e19b58b Make threading work queue platform abstracted 2017-06-18 20:25:57 +10:00
5a6564fa94 Start creating multithreading work queue 2017-06-17 22:25:29 +10:00
64fb913239 Add auto scoped memory regions 2017-06-17 17:57:06 +10:00
35bdbb65de Platform ability to query system (logical) cores 2017-06-17 16:20:35 +10:00
11 changed files with 3165 additions and 1509 deletions

View File

@ -11,7 +11,7 @@
PlatformFlags globalDTRPlatformFlags; PlatformFlags globalDTRPlatformFlags;
// #include <algorithm> // #include <algorithm>
void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const input, void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input,
PlatformMemory *const memory) PlatformMemory *const memory)
{ {
#if 1 #if 1
@ -835,11 +835,11 @@ void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const in
#if 1 #if 1
char pText[32] = {}; char pText[32] = {};
Dqn_sprintf(pText, "(%1.0f, %1.0f)", origP.x, origP.y); Dqn_sprintf(pText, "(%1.0f, %1.0f)", origP.x, origP.y);
DTRRender_Text(renderBuffer, state->font, DTRRender_Text(renderContext, state->font,
DqnV2_2f(p.x + radius.x + 5, p.y - (state->font.sizeInPt * 0.40f)), pText, DqnV2_2f(p.x + radius.x + 5, p.y - (state->font.sizeInPt * 0.40f)), pText,
textColor); textColor);
#endif #endif
DTRRender_Rectangle(renderBuffer, p - radius, p + radius, pColor); DTRRender_Rectangle(renderContext, p - radius, p + radius, pColor);
} }
DqnV2 halfRadius = radius * 0.5f; DqnV2 halfRadius = radius * 0.5f;
@ -851,10 +851,10 @@ void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const in
char pText[32] = {}; char pText[32] = {};
Dqn_sprintf(pText, "(%1.0f, %1.0f)", origP.x, origP.y); Dqn_sprintf(pText, "(%1.0f, %1.0f)", origP.x, origP.y);
DTRRender_Text(renderBuffer, state->font, DTRRender_Text(renderContext, state->font,
DqnV2_2f(p.x + radius.x + 5, p.y - (state->font.sizeInPt * 0.40f)), pText, DqnV2_2f(p.x + radius.x + 5, p.y - (state->font.sizeInPt * 0.40f)), pText,
textColor); textColor);
DTRRender_Rectangle(renderBuffer, p - radius, p + radius, pColor); DTRRender_Rectangle(renderContext, p - radius, p + radius, pColor);
if (i + 1 <= skyPIndex && i > 0) if (i + 1 <= skyPIndex && i > 0)
{ {
@ -863,7 +863,7 @@ void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const in
DqnV2 pMid = p + halfRadius; DqnV2 pMid = p + halfRadius;
DqnV2 prevPMid = prevP + halfRadius; DqnV2 prevPMid = prevP + halfRadius;
DTRRender_Line(renderBuffer, DqnV2i_V2(prevPMid), DqnV2i_V2(pMid), DTRRender_Line(renderContext, DqnV2i_V2(prevPMid), DqnV2i_V2(pMid),
DqnV4_4f(255, 0, 0, 255)); DqnV4_4f(255, 0, 0, 255));
} }
} }
@ -895,10 +895,16 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
state = (DTRState *)memory->context; state = (DTRState *)memory->context;
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Init Memory Stacks // Init
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
DqnMemStack *const assetStack = &memory->assetStack; DqnMemStack *const assetStack = &memory->assetStack;
DqnMemStack *const tempStack = &memory->tempStack; DqnMemStack *const tempStack = &memory->tempStack;
state->renderLock = input->api.LockInit(&memory->mainStack);
if (!state->renderLock)
{
// TODO(doyle): Not enough memory die gracefully
DQN_ASSERT(DQN_INVALID_CODE_PATH);
}
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Init Assets // Init Assets
@ -929,145 +935,184 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
if (DTR_DEBUG) if (DTR_DEBUG)
{ {
DTRDebug_TestMeshFaceAndVertexParser(&state->mesh); DTRDebug_TestMeshFaceAndVertexParser(&state->mesh);
bool regionValid;
DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->tempStack); auto memRegion = DqnMemStackTempRegionGuard(&memory->tempStack, &regionValid);
DTRBitmap test = {}; if (regionValid)
DTRAsset_LoadBitmap(input->api, assetStack, &memory->tempStack, &test, "byte_read_check.bmp"); {
DqnMemStack_EndTempRegion(tmp); DTRBitmap test = {};
DTRAsset_LoadBitmap(input->api, assetStack, &memory->tempStack, &test,
"byte_read_check.bmp");
}
} }
} }
DqnTempMemStack tempStackMemRegion = DqnMemStack_BeginTempRegion(&memory->tempStack);
size_t debugSize = DQN_MEGABYTE(1);
u8 *debugMemory = (u8 *)DqnMemStack_Push(&memory->tempStack, debugSize);
DqnMemStack_InitWithFixedMem(&globalDebug.memStack, debugMemory, debugSize);
DTRDebug_BeginCycleCount("DTR_Update", DTRDebugCycleCount_DTR_Update);
DTRRenderBuffer renderBuffer = {};
renderBuffer.width = platformRenderBuffer->width;
renderBuffer.height = platformRenderBuffer->height;
renderBuffer.bytesPerPixel = platformRenderBuffer->bytesPerPixel;
renderBuffer.memory = (u8 *)platformRenderBuffer->memory;
u32 zBufferSize = platformRenderBuffer->width * platformRenderBuffer->height;
renderBuffer.zBuffer = (f32 *)DqnMemStack_Push(&memory->tempStack,
zBufferSize * sizeof(*renderBuffer.zBuffer));
for (u32 i = 0; i < zBufferSize; i++) renderBuffer.zBuffer[i] = DQN_F32_MIN;
////////////////////////////////////////////////////////////////////////////
// Update and Render
////////////////////////////////////////////////////////////////////////////
DTRRender_Clear(&renderBuffer, DqnV3_3f(0.5f, 0.0f, 1.0f));
#if 1
DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1);
DqnV2i bufferMidP = DqnV2i_2f(renderBuffer.width * 0.5f, renderBuffer.height * 0.5f);
f32 rotation = (f32)input->timeNowInS * 0.25f;
// Triangle Drawing
{ {
DqnV4 redTransparent = DqnV4_4f(1, 0, 0, 0.5f); bool regionValid;
auto tempMemRegion = DqnMemStackTempRegionGuard(&memory->tempStack, &regionValid);
i32 boundsOffset = 100; if (regionValid)
DqnV3 t0[3] = {DqnV3_3i(10, 70, 0), DqnV3_3i(50, 160, 0), DqnV3_3i(70, 80, 0)};
DqnV3 t1[3] = {DqnV3_3i(180, 50, 0), DqnV3_3i(150, 1, 0), DqnV3_3i(70, 180, 0)};
DqnV3 t2[3] = {DqnV3_3i(180, 150, 0), DqnV3_3i(120, 160, 0), DqnV3_3i(130, 180, 0)};
DqnV3 t3[3] = {DqnV3_3i(boundsOffset, boundsOffset, 0),
DqnV3_3i(bufferMidP.w, renderBuffer.height - boundsOffset, 0),
DqnV3_3i(renderBuffer.width - boundsOffset, boundsOffset, 0)};
DqnV3 t4[3] = {DqnV3_3i(100, 150, 0), DqnV3_3i(200, 150, 0), DqnV3_3i(200, 250, 0)};
DqnV3 t5[3] = {DqnV3_3i(300, 150, 0), DqnV3_3i(201, 150, 0), DqnV3_3i(200, 250, 0)};
DTRRenderTransform rotatingXform = DTRRender_DefaultTriangleTransform();
rotatingXform.rotation = rotation;
if (1)
{ {
DTRDebug_BeginCycleCount("DTR_Update_RenderPrimitiveTriangles", size_t debugSize = DQN_MEGABYTE(1);
DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles); u8 *debugMemory = (u8 *)DqnMemStack_Push(&memory->tempStack, debugSize);
DqnMemStack_InitWithFixedMem(&globalDebug.memStack, debugMemory, debugSize);
DTRDebug_BeginCycleCount("DTR_Update", DTRDebugCycleCount_DTR_Update);
DTRRender_Triangle(&renderBuffer, t0[0], t0[1], t0[2], colorRed); DTRRenderBuffer renderBuffer = {};
DTRRender_Triangle(&renderBuffer, t1[0], t1[1], t1[2], colorRed); renderBuffer.width = platformRenderBuffer->width;
DTRRender_Triangle(&renderBuffer, t3[0], t3[1], t3[2], colorRed, rotatingXform); renderBuffer.height = platformRenderBuffer->height;
DTRRender_Triangle(&renderBuffer, t2[0], t2[1], t2[2], colorRed); renderBuffer.bytesPerPixel = platformRenderBuffer->bytesPerPixel;
DTRRender_Triangle(&renderBuffer, t4[0], t4[1], t4[2], colorRed); renderBuffer.memory = (u8 *)platformRenderBuffer->memory;
DTRRender_Triangle(&renderBuffer, t5[0], t5[1], t5[2], colorRed); renderBuffer.renderLock = state->renderLock;
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles);
}
if (1) u32 zBufferSize = platformRenderBuffer->width * platformRenderBuffer->height;
{ renderBuffer.zBuffer = (f32 *)DqnMemStack_Push(
LOCAL_PERSIST bool runTinyRendererOnce = false; &memory->tempStack, zBufferSize * sizeof(*renderBuffer.zBuffer));
if (1 && runTinyRendererOnce)
renderBuffer.pixelLockTable = (bool *)DqnMemStack_Push(
&memory->tempStack, zBufferSize * sizeof(*renderBuffer.pixelLockTable));
for (u32 i = 0; i < zBufferSize; i++)
{ {
DTRDebug_RunTinyRenderer(); renderBuffer.zBuffer[i] = DQN_F32_MIN;
runTinyRendererOnce = false; renderBuffer.pixelLockTable[i] = false;
} }
DTRDebug_BeginCycleCount("DTR_Update_RenderModel", DTRDebugCycleCount_DTR_Update_RenderModel); DTRRenderContext renderContext = {};
//////////////////////////////////////////////////////////////////////// renderContext.multithread = true;
// Draw Loaded Model renderContext.renderBuffer = &renderBuffer;
//////////////////////////////////////////////////////////////////////// renderContext.tempStack = &memory->tempStack;
const DqnV3 LIGHT = DqnV3_Normalise(DqnV3_3f(1, -1, 1.0f)); renderContext.api = &input->api;
const f32 MODEL_SCALE = 1; renderContext.jobQueue = input->jobQueue;
DTRMesh *const mesh = &state->mesh; ////////////////////////////////////////////////////////////////////////////
DqnV3 modelP = DqnV3_3f(0, 0, 0); // Update and Render
////////////////////////////////////////////////////////////////////////////
DTRRender_Clear(renderContext, DqnV3_3f(0.5f, 0.0f, 1.0f));
LOCAL_PERSIST f32 modelRotation = 0; #if 1
modelRotation += (input->deltaForFrame * 20.0f); DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1);
DqnV3 axis = DqnV3_3f(0, 1, 0); DqnV2i bufferMidP = DqnV2i_2f(renderBuffer.width * 0.5f, renderBuffer.height * 0.5f);
f32 rotation = (f32)input->timeNowInS * 0.25f;
DTRRenderTransform transform = DTRRender_DefaultTransform(); // Triangle Drawing
transform.scale = DqnV3_1f(MODEL_SCALE); {
transform.rotation = modelRotation; DqnV4 redTransparent = DqnV4_4f(1, 0, 0, 0.5f);
transform.anchor = axis;
DTRRenderLight lighting = {}; i32 boundsOffset = 100;
lighting.mode = DTRRenderShadingMode_Gouraud; DqnV3 t0[3] = {DqnV3_3i(10, 70, 0), DqnV3_3i(50, 160, 0), DqnV3_3i(70, 80, 0)};
lighting.vector = LIGHT; DqnV3 t1[3] = {DqnV3_3i(180, 50, 0), DqnV3_3i(150, 1, 0), DqnV3_3i(70, 180, 0)};
lighting.color = DqnV4_4f(1, 1, 1, 1); DqnV3 t2[3] = {DqnV3_3i(180, 150, 0), DqnV3_3i(120, 160, 0), DqnV3_3i(130, 180, 0)};
DqnV3 t3[3] = {DqnV3_3i(boundsOffset, boundsOffset, 0),
DqnV3_3i(bufferMidP.w, renderBuffer.height - boundsOffset, 0),
DqnV3_3i(renderBuffer.width - boundsOffset, boundsOffset, 0)};
DqnV3 t4[3] = {DqnV3_3i(100, 150, 0), DqnV3_3i(200, 150, 0), DqnV3_3i(200, 250, 0)};
DqnV3 t5[3] = {DqnV3_3i(300, 150, 0), DqnV3_3i(201, 150, 0), DqnV3_3i(200, 250, 0)};
DTRRender_Mesh(&renderBuffer, mesh, lighting, modelP, transform); DTRRenderTransform rotatingXform = DTRRender_DefaultTriangleTransform();
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderModel); rotatingXform.rotation = rotation;
}
}
// Rect drawing if (0)
if (0) {
{ DTRDebug_BeginCycleCount(
DTRRenderTransform transform = DTRRender_DefaultTransform(); "DTR_Update_RenderPrimitiveTriangles",
transform.rotation = rotation + 45; DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles);
DTRRender_Rectangle(&renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f), DTRRender_Triangle(renderContext, t0[0], t0[1], t0[2], colorRed);
DqnV4_4f(0, 1.0f, 1.0f, 1.0f), transform); DTRRender_Triangle(renderContext, t1[0], t1[1], t1[2], colorRed);
} DTRRender_Triangle(renderContext, t3[0], t3[1], t3[2], colorRed, rotatingXform);
DTRRender_Triangle(renderContext, t2[0], t2[1], t2[2], colorRed);
DTRRender_Triangle(renderContext, t4[0], t4[1], t4[2], colorRed);
DTRRender_Triangle(renderContext, t5[0], t5[1], t5[2], colorRed);
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles);
}
// Bitmap drawing if (1)
if (0) {
{ LOCAL_PERSIST bool runTinyRendererOnce = false;
DTRRenderTransform transform = DTRRender_DefaultTransform(); if (1 && runTinyRendererOnce)
transform.scale = DqnV3_1f(2.0f); {
DTRDebug_RunTinyRenderer();
runTinyRendererOnce = false;
}
LOCAL_PERSIST DqnV2 bitmapP = DqnV2_2f(500, 250); DTRDebug_BeginCycleCount("DTR_Update_RenderModel",
bitmapP.x += 2.0f * sinf((f32)input->timeNowInS * 0.5f); DTRDebugCycleCount_DTR_Update_RenderModel);
////////////////////////////////////////////////////////////////////////
// Draw Loaded Model
////////////////////////////////////////////////////////////////////////
const DqnV3 LIGHT = DqnV3_Normalise(DqnV3_3f(1, -1, 1.0f));
const f32 MODEL_SCALE = 1;
DTRMesh *const mesh = &state->mesh;
DqnV3 modelP = DqnV3_3f(0, 0, 0);
f32 cAngle = (f32)input->timeNowInS; LOCAL_PERSIST f32 modelRotation = 0;
DqnV4 color = DqnV4_4f(0.5f + 0.5f * sinf(cAngle), 0.5f + 0.5f * sinf(2.9f * cAngle), modelRotation += (input->deltaForFrame * 20.0f);
0.5f + 0.5f * cosf(10.0f * cAngle), 1.0f); DqnV3 axis = DqnV3_3f(0, 1, 0);
DTRRender_Bitmap(&renderBuffer, &state->bitmap, bitmapP, transform, color);
} DTRRenderTransform transform = DTRRender_DefaultTransform();
transform.scale = DqnV3_1f(MODEL_SCALE);
transform.rotation = modelRotation;
transform.anchor = axis;
DTRRenderLight lighting = {};
lighting.mode = DTRRenderShadingMode_Gouraud;
lighting.vector = LIGHT;
lighting.color = DqnV4_4f(1, 1, 1, 1);
DTRRender_Mesh(renderContext, input->jobQueue, mesh, lighting, modelP,
transform);
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderModel);
}
}
// Rect drawing
if (0)
{
DTRRenderTransform transform = DTRRender_DefaultTransform();
transform.rotation = rotation + 45;
DTRRender_Rectangle(renderContext, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f),
DqnV4_4f(0, 1.0f, 1.0f, 1.0f), transform);
}
// Bitmap drawing
if (0)
{
DTRRenderTransform transform = DTRRender_DefaultTransform();
transform.scale = DqnV3_1f(2.0f);
LOCAL_PERSIST DqnV2 bitmapP = DqnV2_2f(500, 250);
bitmapP.x += 2.0f * sinf((f32)input->timeNowInS * 0.5f);
f32 cAngle = (f32)input->timeNowInS;
DqnV4 color =
DqnV4_4f(0.5f + 0.5f * sinf(cAngle), 0.5f + 0.5f * sinf(2.9f * cAngle),
0.5f + 0.5f * cosf(10.0f * cAngle), 1.0f);
DTRRender_Bitmap(renderContext, &state->bitmap, bitmapP, transform, color);
}
#else #else
// CompAssignment(renderBuffer, input, memory); // CompAssignment(renderBuffer, input, memory);
#endif #endif
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update); DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update);
DTRDebug_Update(state, &renderBuffer, input, memory); DTRDebug_Update(state, renderContext, input, memory);
DqnMemStack_EndTempRegion(tempStackMemRegion); }
while (input->api.QueueTryExecuteNextJob(input->jobQueue) ||
!input->api.QueueAllJobsComplete(input->jobQueue))
;
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// End Update // End Update
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
for (i32 i = 0; i < DQN_ARRAY_COUNT(memory->stacks); i++) if (DTR_DEBUG)
DQN_ASSERT(memory->stacks[i].tempStackCount == 0); {
DQN_ASSERT(input->api.QueueAllJobsComplete(input->jobQueue));
for (i32 i = 0; i < DQN_ARRAY_COUNT(memory->stacks); i++)
{
if (&memory->stacks[i] == &memory->tempStack) continue;
DQN_ASSERT(memory->stacks[i].tempRegionCount == 0);
}
DqnMemStack_ClearCurrBlock(&memory->tempStack, true);
}
} }

View File

@ -13,6 +13,8 @@ typedef struct DTRState
DTRFont font; DTRFont font;
DTRBitmap bitmap; DTRBitmap bitmap;
DTRMesh mesh; DTRMesh mesh;
struct PlatformLock *renderLock;
} DTRState; } DTRState;
extern PlatformFlags globalDTRPlatformFlags; extern PlatformFlags globalDTRPlatformFlags;

View File

@ -196,16 +196,26 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly)) if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
return false; // TODO(doyle): Logging return false; // TODO(doyle): Logging
bool result = false; WavefModel dummy_ = {};
DqnTempMemStack tmpAssetRegion = DqnMemStack_BeginTempRegion(memStack); WavefModel *obj = &dummy_;
u8 *rawBytes = (u8 *)DqnMemStack_Push(memStack, file.size);
size_t bytesRead = api.FileRead(&file, rawBytes, file.size);
size_t fileSize = file.size;
DqnMemAPI memAPI = {}; DqnMemAPI memAPI = {};
memAPI.callback = DumbDynamicArrayMemAPICallback; memAPI.callback = DumbDynamicArrayMemAPICallback;
memAPI.userContext = memStack; memAPI.userContext = memStack;
bool result = false;
DqnMemStackTempRegion tmpAssetRegion;
if (!DqnMemStackTempRegion_Begin(&tmpAssetRegion, memStack))
{
// TODO(doyle): Logging
DQN_ASSERT(DQN_INVALID_CODE_PATH);
goto cleanup;
}
u8 *rawBytes = (u8 *)DqnMemStack_Push(memStack, file.size);
size_t bytesRead = api.FileRead(&file, rawBytes, file.size);
size_t fileSize = file.size;
enum WavefVertexType { enum WavefVertexType {
WavefVertexType_Invalid, WavefVertexType_Invalid,
WavefVertexType_Geometric, WavefVertexType_Geometric,
@ -230,9 +240,6 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac
// to a new memstack block such that all the data is compacted together in // to a new memstack block such that all the data is compacted together in
// memory for locality. Then just throw away the intermediate // memory for locality. Then just throw away the intermediate
// representation. // representation.
WavefModel dummy_ = {};
WavefModel *obj = &dummy_;
if (bytesRead != file.size) goto cleanup; if (bytesRead != file.size) goto cleanup;
if (!WavefModelInit(obj, memAPI)) goto cleanup; if (!WavefModelInit(obj, memAPI)) goto cleanup;
@ -586,7 +593,7 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac
DQN_ASSERT(DQN_INVALID_CODE_PATH); DQN_ASSERT(DQN_INVALID_CODE_PATH);
} }
DqnMemStack_EndTempRegion(tmpAssetRegion); DqnMemStackTempRegion_End(tmpAssetRegion);
if (modelBlock) if (modelBlock)
{ {
result = true; result = true;
@ -599,7 +606,7 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac
cleanup: cleanup:
api.FileClose(&file); api.FileClose(&file);
if(!result) DqnMemStack_EndTempRegion(tmpAssetRegion); if(!result) DqnMemStackTempRegion_End(tmpAssetRegion);
return result; return result;
} }
@ -623,14 +630,22 @@ bool DTRAsset_LoadFontToBitmap(const PlatformAPI api, DqnMemStack *const memStac
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly)) if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
return false; // TODO(doyle): Logging return false; // TODO(doyle): Logging
bool result = false;
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tmpMemStack);
u8 *rawBytes = (u8 *)DqnMemStack_Push(tmpMemStack, file.size);
size_t bytesRead = api.FileRead(&file, rawBytes, file.size);
stbtt_fontinfo fontInfo = {}; stbtt_fontinfo fontInfo = {};
stbtt_pack_context fontPackContext = {}; stbtt_pack_context fontPackContext = {};
bool result = false;
bool regionValid;
auto tmpMemRegion = DqnMemStackTempRegionGuard(tmpMemStack, &regionValid);
if (!regionValid)
{
// TODO(doyle): Logging
DQN_ASSERT(DQN_INVALID_CODE_PATH);
goto cleanup;
}
u8 *rawBytes = (u8 *)DqnMemStack_Push(tmpMemStack, file.size);
size_t bytesRead = api.FileRead(&file, rawBytes, file.size);
if (bytesRead != file.size || stbtt_InitFont(&fontInfo, rawBytes, 0) == 0) if (bytesRead != file.size || stbtt_InitFont(&fontInfo, rawBytes, 0) == 0)
{ {
DQN_ASSERT(DQN_INVALID_CODE_PATH); DQN_ASSERT(DQN_INVALID_CODE_PATH);
@ -692,7 +707,6 @@ bool DTRAsset_LoadFontToBitmap(const PlatformAPI api, DqnMemStack *const memStac
*font = loadedFont; *font = loadedFont;
cleanup: cleanup:
DqnMemStack_EndTempRegion(tmpMemRegion);
api.FileClose(&file); api.FileClose(&file);
return result; return result;
@ -753,9 +767,9 @@ bool DTRAsset_LoadBitmap(const PlatformAPI api, DqnMemStack *const memStack,
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly)) if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
return result; return result;
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack); DqnMemStackTempRegionGuard tmpMemRegion = tempStack->TempRegionGuard();
u8 *const rawData = (u8 *)DqnMemStack_Push (tempStack, file.size); u8 *const rawData = (u8 *)DqnMemStack_Push(tempStack, file.size);
size_t bytesRead = api.FileRead (&file, rawData, file.size); size_t bytesRead = api.FileRead(&file, rawData, file.size);
if (bytesRead != file.size) goto cleanup; if (bytesRead != file.size) goto cleanup;
@ -830,7 +844,6 @@ bool DTRAsset_LoadBitmap(const PlatformAPI api, DqnMemStack *const memStack,
cleanup: cleanup:
globalSTBImageAllocator = NULL; globalSTBImageAllocator = NULL;
DqnMemStack_EndTempRegion(tmpMemRegion);
api.FileClose(&file); api.FileClose(&file);
return result; return result;

View File

@ -77,31 +77,32 @@ void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *cons
} }
} }
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack); bool regionValid;
auto memRegion = DqnMemStackTempRegionGuard(tempStack, &regionValid);
size_t bufSize = DQN_MEGABYTE(16); if (regionValid)
char *bufString = (char *)DqnMemStack_Push(tempStack, bufSize);
char *bufPtr = bufString;
for (i32 i = 0; i < renderBuffer->width * renderBuffer->height; i++)
{ {
size_t bufSize = DQN_MEGABYTE(16);
f32 zValue = renderBuffer->zBuffer[i]; char *bufString = (char *)DqnMemStack_Push(tempStack, bufSize);
if (zValue == DQN_F32_MIN) continue; char *bufPtr = bufString;
i32 chWritten = Dqn_sprintf(bufPtr, "index %06d: %05.5f\n", i, zValue); for (i32 i = 0; i < renderBuffer->width * renderBuffer->height; i++)
if ((bufPtr + chWritten) > (bufString + bufSize))
{ {
size_t bufPtrAddr = (size_t)(bufPtr + chWritten);
size_t bufStringAddr = (size_t)(bufString + bufSize); f32 zValue = renderBuffer->zBuffer[i];
DQN_ASSERT(DQN_INVALID_CODE_PATH); if (zValue == DQN_F32_MIN) continue;
i32 chWritten = Dqn_sprintf(bufPtr, "index %06d: %05.5f\n", i, zValue);
if ((bufPtr + chWritten) > (bufString + bufSize))
{
size_t bufPtrAddr = (size_t)(bufPtr + chWritten);
size_t bufStringAddr = (size_t)(bufString + bufSize);
DQN_ASSERT(DQN_INVALID_CODE_PATH);
}
bufPtr += chWritten;
} }
bufPtr += chWritten;
size_t writeSize = (size_t)bufPtr - (size_t)bufString;
size_t bytesWritten = api->FileWrite(&file, (u8 *)bufString, writeSize);
api->FileClose(&file);
} }
size_t writeSize = (size_t)bufPtr - (size_t)bufString;
size_t bytesWritten = api->FileWrite(&file, (u8 *)bufString, writeSize);
api->FileClose(&file);
DqnMemStack_EndTempRegion(tmpMemRegion);
} }
} }
@ -118,7 +119,7 @@ void DTRDebug_PushText(const char *const formatStr, ...)
if (DTR_DEBUG) if (DTR_DEBUG)
{ {
DTRDebug *const debug = &globalDebug; DTRDebug *const debug = &globalDebug;
if (!debug->renderBuffer) return; if (!debug->renderContext->renderBuffer) return;
char str[1024] = {}; char str[1024] = {};
@ -130,7 +131,7 @@ void DTRDebug_PushText(const char *const formatStr, ...)
} }
va_end(argList); va_end(argList);
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str, DTRRender_Text(*debug->renderContext, *debug->font, debug->displayP, str,
debug->displayColor); debug->displayColor);
debug->displayP.y += globalDebug.displayYOffset; debug->displayP.y += globalDebug.displayYOffset;
} }
@ -199,25 +200,25 @@ FILE_SCOPE void PushMemStackText(const char *const name, const DqnMemStack *cons
Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld: wasted: %_$lld", name, numBlocks, Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld: wasted: %_$lld", name, numBlocks,
totalUsed, totalSize, totalWastedKb); totalUsed, totalSize, totalWastedKb);
DTRRender_Text(globalDebug.renderBuffer, *globalDebug.font, DTRRender_Text(*globalDebug.renderContext, *globalDebug.font,
globalDebug.displayP, str, globalDebug.displayColor); globalDebug.displayP, str, globalDebug.displayColor);
globalDebug.displayP.y += globalDebug.displayYOffset; globalDebug.displayP.y += globalDebug.displayYOffset;
} }
} }
void DTRDebug_Update(DTRState *const state, void DTRDebug_Update(DTRState *const state,
DTRRenderBuffer *const renderBuffer, DTRRenderContext renderContext,
PlatformInput *const input, PlatformMemory *const memory) PlatformInput *const input, PlatformMemory *const memory)
{ {
if (DTR_DEBUG) if (DTR_DEBUG)
{ {
DTRDebug *const debug = &globalDebug; DTRDebug *const debug = &globalDebug;
debug->renderBuffer = renderBuffer; debug->renderContext = &renderContext;
debug->input = input; debug->input = input;
debug->font = &state->font; debug->font = &state->font;
debug->displayColor = DqnV4_4f(1, 1, 1, 1); debug->displayColor = DqnV4_4f(1, 1, 1, 1);
if (debug->font->bitmap && debug->renderBuffer) if (debug->font->bitmap && debug->renderContext)
{ {
debug->displayYOffset = -(i32)(state->font.sizeInPt + 0.5f); debug->displayYOffset = -(i32)(state->font.sizeInPt + 0.5f);
DQN_ASSERT(globalDebug.displayYOffset < 0); DQN_ASSERT(globalDebug.displayYOffset < 0);
@ -270,7 +271,7 @@ void DTRDebug_Update(DTRState *const state,
// End Debug Update // End Debug Update
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
debug->displayP = debug->displayP =
DqnV2_2i(0, debug->renderBuffer->height + globalDebug.displayYOffset); DqnV2_2i(0, debug->renderContext->renderBuffer->height + globalDebug.displayYOffset);
for (i32 i = 0; i < DQN_ARRAY_COUNT(debug->counter); i++) for (i32 i = 0; i < DQN_ARRAY_COUNT(debug->counter); i++)
debug->counter[i] = 0; debug->counter[i] = 0;

View File

@ -88,10 +88,10 @@ typedef struct DTRDebugCycles
typedef struct DTRDebug typedef struct DTRDebug
{ {
struct DTRFont *font; struct DTRFont *font;
struct DTRRenderBuffer *renderBuffer; struct DTRRenderContext *renderContext;
struct PlatformInput *input; struct PlatformInput *input;
DqnMemStack memStack; DqnMemStack memStack;
DqnV4 displayColor; DqnV4 displayColor;
DqnV2 displayP; DqnV2 displayP;

View File

@ -4,6 +4,11 @@
#include "dqn.h" #include "dqn.h"
#include <intrin.h> #include <intrin.h>
typedef void PlatformAPI_DieGracefully();
////////////////////////////////////////////////////////////////////////////////
// Platform File I/O
////////////////////////////////////////////////////////////////////////////////
enum PlatformFilePermissionFlag enum PlatformFilePermissionFlag
{ {
PlatformFilePermissionFlag_Read = (1 << 0), PlatformFilePermissionFlag_Read = (1 << 0),
@ -24,20 +29,71 @@ typedef struct PlatformFile
u32 permissionFlags; u32 permissionFlags;
} PlatformFile; } PlatformFile;
// File I/O API
typedef bool PlatformAPI_FileOpen (const char *const path, PlatformFile *const file, const u32 permissionFlags, const enum PlatformFileAction actionFlags); typedef bool PlatformAPI_FileOpen (const char *const path, PlatformFile *const file, const u32 permissionFlags, const enum PlatformFileAction actionFlags);
typedef size_t PlatformAPI_FileRead (PlatformFile *const file, u8 *const buf, const size_t bytesToRead); // Return bytes read typedef size_t PlatformAPI_FileRead (PlatformFile *const file, u8 *const buf, const size_t bytesToRead); // Return bytes read
typedef size_t PlatformAPI_FileWrite(PlatformFile *const file, u8 *const buf, const size_t numBytesToWrite); // Return bytes read typedef size_t PlatformAPI_FileWrite(PlatformFile *const file, u8 *const buf, const size_t numBytesToWrite); // Return bytes read
typedef void PlatformAPI_FileClose(PlatformFile *const file); typedef void PlatformAPI_FileClose(PlatformFile *const file);
typedef void PlatformAPI_Print (const char *const string); typedef void PlatformAPI_Print (const char *const string);
////////////////////////////////////////////////////////////////////////////////
// Platform Multithreading
////////////////////////////////////////////////////////////////////////////////
// PlatformJobQueue must be implemented in platform code. It simply needs to
// fullfill the API and be able to accept PlatformJob structs and execute them.
typedef struct PlatformJobQueue PlatformJobQueue;
typedef void PlatformJob_Callback(PlatformJobQueue *const queue, void *const userData);
typedef struct PlatformJob
{
PlatformJob_Callback *callback;
void *userData;
} PlatformJob;
// Multithreading API
typedef bool PlatformAPI_QueueAddJob (PlatformJobQueue *const queue, const PlatformJob job);
typedef bool PlatformAPI_QueueTryExecuteNextJob(PlatformJobQueue *const queue);
typedef bool PlatformAPI_QueueAllJobsComplete (PlatformJobQueue *const queue);
typedef u32 PlatformAPI_AtomicCompareSwap(u32 volatile *dest, u32 swapVal, u32 compareVal);
////////////////////////////////////////////////////////////////////////////////
// Platform Locks
////////////////////////////////////////////////////////////////////////////////
typedef struct PlatformLock PlatformLock;
typedef PlatformLock *PlatformAPI_LockInit (DqnMemStack *const stack);
typedef void PlatformAPI_LockAcquire(PlatformLock *const lock);
typedef void PlatformAPI_LockRelease(PlatformLock *const lock);
typedef void PlatformAPI_LockDelete (PlatformLock *const lock);
////////////////////////////////////////////////////////////////////////////////
// Platform API for Game to Use
////////////////////////////////////////////////////////////////////////////////
typedef struct PlatformAPI typedef struct PlatformAPI
{ {
PlatformAPI_FileOpen *FileOpen; PlatformAPI_FileOpen *FileOpen;
PlatformAPI_FileRead *FileRead; PlatformAPI_FileRead *FileRead;
PlatformAPI_FileWrite *FileWrite; PlatformAPI_FileWrite *FileWrite;
PlatformAPI_FileClose *FileClose; PlatformAPI_FileClose *FileClose;
PlatformAPI_Print *Print; PlatformAPI_Print *Print;
PlatformAPI_QueueAddJob *QueueAddJob;
PlatformAPI_QueueTryExecuteNextJob *QueueTryExecuteNextJob;
PlatformAPI_QueueAllJobsComplete *QueueAllJobsComplete;
PlatformAPI_AtomicCompareSwap *AtomicCompareSwap;
PlatformAPI_LockInit *LockInit;
PlatformAPI_LockAcquire *LockAcquire;
PlatformAPI_LockRelease *LockRelease;
PlatformAPI_LockDelete *LockDelete;
PlatformAPI_DieGracefully *DieGracefully;
} PlatformAPI; } PlatformAPI;
////////////////////////////////////////////////////////////////////////////////
// Platform Input
////////////////////////////////////////////////////////////////////////////////
enum Key enum Key
{ {
key_up, key_up,
@ -96,8 +152,9 @@ typedef struct PlatformInput
f64 timeNowInS; f64 timeNowInS;
PlatformFlags flags; PlatformFlags flags;
PlatformAPI api; PlatformAPI api;
PlatformMouse mouse; PlatformMouse mouse;
PlatformJobQueue *jobQueue;
union { union {
KeyState key[key_count]; KeyState key[key_count];
struct struct
@ -131,6 +188,9 @@ typedef struct PlatformInput
}; };
} PlatformInput; } PlatformInput;
////////////////////////////////////////////////////////////////////////////////
// Platform Memory
////////////////////////////////////////////////////////////////////////////////
typedef struct PlatformMemory typedef struct PlatformMemory
{ {
union { union {
@ -146,6 +206,9 @@ typedef struct PlatformMemory
void *context; void *context;
} PlatformMemory; } PlatformMemory;
////////////////////////////////////////////////////////////////////////////////
// Platform Frame Buffer
////////////////////////////////////////////////////////////////////////////////
typedef struct PlatformRenderBuffer typedef struct PlatformRenderBuffer
{ {
i32 width; i32 width;

View File

@ -121,9 +121,10 @@ inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color)
} }
// IMPORTANT(doyle): Color is expected to be premultiplied already // IMPORTANT(doyle): Color is expected to be premultiplied already
FILE_SCOPE inline void SetPixel(DTRRenderBuffer *const renderBuffer, const i32 x, const i32 y, FILE_SCOPE inline void SetPixel(DTRRenderContext context, const i32 x, const i32 y,
DqnV4 color, const enum ColorSpace colorSpace = ColorSpace_SRGB) DqnV4 color, const enum ColorSpace colorSpace = ColorSpace_SRGB)
{ {
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!renderBuffer) return; if (!renderBuffer) return;
if (x < 0 || x > (renderBuffer->width - 1)) return; if (x < 0 || x > (renderBuffer->width - 1)) return;
if (y < 0 || y > (renderBuffer->height - 1)) return; if (y < 0 || y > (renderBuffer->height - 1)) return;
@ -189,15 +190,18 @@ FILE_SCOPE inline void SetPixel(DTRRenderBuffer *const renderBuffer, const i32 x
DTRDebug_CounterIncrement(DTRDebugCounter_SetPixels); DTRDebug_CounterIncrement(DTRDebugCounter_SetPixels);
} }
void DTRRender_Text(DTRRenderBuffer *const renderBuffer, void DTRRender_Text(DTRRenderContext context,
const DTRFont font, DqnV2 pos, const char *const text, const DTRFont font, DqnV2 pos, const char *const text,
DqnV4 color, i32 len) DqnV4 color, i32 len)
{ {
if (!text) return; if (!text) return;
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!font.bitmap || !font.atlas || !renderBuffer) return; if (!font.bitmap || !font.atlas || !renderBuffer) return;
DTR_DEBUG_EP_TIMED_FUNCTION(); DTR_DEBUG_EP_TIMED_FUNCTION();
if (len == -1) len = Dqn_strlen(text);
if (len == -1) len = DqnStr_Len(text);
i32 index = 0; i32 index = 0;
color = DTRRender_SRGB1ToLinearSpaceV4(color); color = DTRRender_SRGB1ToLinearSpaceV4(color);
@ -262,7 +266,7 @@ void DTRRender_Text(DTRRenderBuffer *const renderBuffer,
i32 actualX = (i32)(screenRect.min.x + x); i32 actualX = (i32)(screenRect.min.x + x);
i32 actualY = (i32)(screenRect.min.y + y - fontHeightOffset); i32 actualY = (i32)(screenRect.min.y + y - fontHeightOffset);
SetPixel(renderBuffer, actualX, actualY, resultColor, ColorSpace_Linear); SetPixel(context, actualX, actualY, resultColor, ColorSpace_Linear);
} }
} }
} }
@ -287,9 +291,10 @@ FILE_SCOPE void TransformPoints(const DqnV2 origin, DqnV2 *const pList,
} }
} }
void DTRRender_Line(DTRRenderBuffer *const renderBuffer, DqnV2i a, void DTRRender_Line(DTRRenderContext context, DqnV2i a,
DqnV2i b, DqnV4 color) DqnV2i b, DqnV4 color)
{ {
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!renderBuffer) return; if (!renderBuffer) return;
DTR_DEBUG_EP_TIMED_FUNCTION(); DTR_DEBUG_EP_TIMED_FUNCTION();
@ -339,7 +344,7 @@ void DTRRender_Line(DTRRenderBuffer *const renderBuffer, DqnV2i a,
for (i32 iterateX = 0; iterateX < numIterations; iterateX++) for (i32 iterateX = 0; iterateX < numIterations; iterateX++)
{ {
newX = a.x + iterateX; newX = a.x + iterateX;
SetPixel(renderBuffer, *plotX, *plotY, color, ColorSpace_Linear); SetPixel(context, *plotX, *plotY, color, ColorSpace_Linear);
distAccumulator += distFromPixelOrigin; distAccumulator += distFromPixelOrigin;
if (distAccumulator > run) if (distAccumulator > run)
@ -407,10 +412,13 @@ FILE_SCOPE DqnRect GetBoundingBox(const DqnV2 *const pList, const i32 numP)
return result; return result;
} }
void DTRRender_Rectangle(DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, void DTRRender_Rectangle(DTRRenderContext context, DqnV2 min, DqnV2 max,
DqnV4 color, const DTRRenderTransform transform) DqnV4 color, const DTRRenderTransform transform)
{ {
DTR_DEBUG_EP_TIMED_FUNCTION(); DTR_DEBUG_EP_TIMED_FUNCTION();
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!renderBuffer) return;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Transform vertexes // Transform vertexes
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -461,7 +469,7 @@ void DTRRender_Rectangle(DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 m
} }
} }
if (pIsInside) SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear); if (pIsInside) SetPixel(context, bufferX, bufferY, color, ColorSpace_Linear);
} }
} }
} }
@ -473,7 +481,7 @@ void DTRRender_Rectangle(DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 m
for (i32 x = 0; x < clippedSize.w; x++) for (i32 x = 0; x < clippedSize.w; x++)
{ {
i32 bufferX = (i32)clippedRect.min.x + x; i32 bufferX = (i32)clippedRect.min.x + x;
SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear); SetPixel(context, bufferX, bufferY, color, ColorSpace_Linear);
} }
} }
} }
@ -485,20 +493,20 @@ void DTRRender_Rectangle(DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 m
{ {
// Draw Bounding box // Draw Bounding box
{ {
DTRRender_Line(renderBuffer, DqnV2i_2f(min.x, min.y), DqnV2i_2f(min.x, max.y), color); DTRRender_Line(context, DqnV2i_2f(min.x, min.y), DqnV2i_2f(min.x, max.y), color);
DTRRender_Line(renderBuffer, DqnV2i_2f(min.x, max.y), DqnV2i_2f(max.x, max.y), color); DTRRender_Line(context, DqnV2i_2f(min.x, max.y), DqnV2i_2f(max.x, max.y), color);
DTRRender_Line(renderBuffer, DqnV2i_2f(max.x, max.y), DqnV2i_2f(max.x, min.y), color); DTRRender_Line(context, DqnV2i_2f(max.x, max.y), DqnV2i_2f(max.x, min.y), color);
DTRRender_Line(renderBuffer, DqnV2i_2f(max.x, min.y), DqnV2i_2f(min.x, min.y), color); DTRRender_Line(context, DqnV2i_2f(max.x, min.y), DqnV2i_2f(min.x, min.y), color);
} }
// Draw rotating outline // Draw rotating outline
if (transform.rotation > 0) if (transform.rotation > 0)
{ {
DqnV4 green = DqnV4_4f(0, 1, 0, 1); DqnV4 green = DqnV4_4f(0, 1, 0, 1);
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green); DTRRender_Line(context, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green);
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green); DTRRender_Line(context, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green);
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), green); DTRRender_Line(context, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), green);
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[3]), DqnV2i_V2(pList[0]), green); DTRRender_Line(context, DqnV2i_V2(pList[3]), DqnV2i_V2(pList[0]), green);
} }
} }
@ -609,10 +617,12 @@ FILE_SCOPE inline DqnV2 Get2DOriginFromTransformAnchor(const DqnV2 p1, const Dqn
} }
// color: _mm_set_ps(a, b, g, r) ie. 0=r, 1=g, 2=b, 3=a // color: _mm_set_ps(a, b, g, r) ie. 0=r, 1=g, 2=b, 3=a
FILE_SCOPE inline void SIMDSetPixel(DTRRenderBuffer *const renderBuffer, const i32 x, const i32 y, FILE_SCOPE inline void SIMDSetPixel(DTRRenderContext context, const i32 x, const i32 y,
__m128 color, __m128 color,
const enum ColorSpace colorSpace = ColorSpace_SRGB) const enum ColorSpace colorSpace = ColorSpace_SRGB)
{ {
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!renderBuffer) return; if (!renderBuffer) return;
if (x < 0 || x > (renderBuffer->width - 1)) return; if (x < 0 || x > (renderBuffer->width - 1)) return;
if (y < 0 || y > (renderBuffer->height - 1)) return; if (y < 0 || y > (renderBuffer->height - 1)) return;
@ -620,22 +630,22 @@ FILE_SCOPE inline void SIMDSetPixel(DTRRenderBuffer *const renderBuffer, const i
DTR_DEBUG_EP_TIMED_FUNCTION(); DTR_DEBUG_EP_TIMED_FUNCTION();
DebugSIMDAssertColorInRange(color, 0.0f, 1.0f); DebugSIMDAssertColorInRange(color, 0.0f, 1.0f);
u32 *const bitmapPtr = (u32 *)renderBuffer->memory;
const u32 pitchInU32 = (renderBuffer->width * renderBuffer->bytesPerPixel) / 4;
// If some alpha is involved, we need to apply gamma correction, but if the // If some alpha is involved, we need to apply gamma correction, but if the
// new pixel is totally opaque or invisible then we're just flat out // new pixel is totally opaque or invisible then we're just flat out
// overwriting/keeping the state of the pixel so we can save cycles by skipping. // overwriting/keeping the state of the pixel so we can save cycles by skipping.
f32 alpha = ((f32 *)&color)[3]; f32 alpha = ((f32 *)&color)[3];
bool needGammaFix = (alpha > 0.0f || alpha < (1.0f + COLOR_EPSILON)) && (colorSpace == ColorSpace_SRGB); bool needGammaFix =
(alpha > 0.0f || alpha < (1.0f + COLOR_EPSILON)) && (colorSpace == ColorSpace_SRGB);
if (needGammaFix) color = SIMDSRGB1ToLinearSpace(color); if (needGammaFix) color = SIMDSRGB1ToLinearSpace(color);
// Format: u32 == (XX, RR, GG, BB) // Format: u32 == (XX, RR, GG, BB)
u32 *const bitmapPtr = (u32 *)renderBuffer->memory;
const u32 pitchInU32 = (renderBuffer->width * renderBuffer->bytesPerPixel) / 4;
u32 srcPixel = bitmapPtr[x + (y * pitchInU32)]; u32 srcPixel = bitmapPtr[x + (y * pitchInU32)];
__m128 src = _mm_set_ps(0, __m128 src = _mm_set_ps(0, (f32)((srcPixel >> 0) & 0xFF),
(f32)((srcPixel >> 0) & 0xFF), (f32)((srcPixel >> 8) & 0xFF),
(f32)((srcPixel >> 8) & 0xFF), (f32)((srcPixel >> 16) & 0xFF));
(f32)((srcPixel >> 16) & 0xFF));
src = SIMDSRGB255ToLinearSpace1(src); src = SIMDSRGB255ToLinearSpace1(src);
f32 invA = 1 - alpha; f32 invA = 1 - alpha;
@ -654,12 +664,10 @@ FILE_SCOPE inline void SIMDSetPixel(DTRRenderBuffer *const renderBuffer, const i
f32 destB = ((f32 *)&dest)[2]; f32 destB = ((f32 *)&dest)[2];
u32 pixel = // ((u32)(destA) << 24 | u32 pixel = // ((u32)(destA) << 24 |
(u32)(destR) << 16 | (u32)(destR) << 16 |
(u32)(destG) << 8 | (u32)(destG) << 8 |
(u32)(destB) << 0; (u32)(destB) << 0;
bitmapPtr[x + (y * pitchInU32)] = pixel; bitmapPtr[x + (y * pitchInU32)] = pixel;
DTRDebug_CounterIncrement(DTRDebugCounter_SetPixels);
} }
// colorModulate: _mm_set_ps(a, b, g, r) ie. 0=r, 1=g, 2=b, 3=a // colorModulate: _mm_set_ps(a, b, g, r) ie. 0=r, 1=g, 2=b, 3=a
@ -708,7 +716,7 @@ FILE_SCOPE __m128 SIMDSampleTextureForTriangle(const DTRBitmap *const texture, c
// IMPORTANT: Debug Markers can _NOT_ be used in primitive rendering functions, // IMPORTANT: Debug Markers can _NOT_ be used in primitive rendering functions,
// ie. any render function that is used in this call because it'll call into // ie. any render function that is used in this call because it'll call into
// itself infinitely. // itself infinitely.
FILE_SCOPE void DebugRenderMarkers(DTRRenderBuffer *const renderBuffer, const DqnV2 *const pList, FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const pList,
const i32 pListSize, const DTRRenderTransform transform, const i32 pListSize, const DTRRenderTransform transform,
bool drawBoundingBox, bool drawBasis, bool drawVertexMarkers) bool drawBoundingBox, bool drawBasis, bool drawVertexMarkers)
{ {
@ -725,10 +733,10 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderBuffer *const renderBuffer, const Dq
{ {
DqnRect bounds = GetBoundingBox(pList, pListSize); DqnRect bounds = GetBoundingBox(pList, pListSize);
DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.min.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.max.y), red); DTRRender_Line(context, DqnV2i_2f(bounds.min.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.max.y), red);
DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.min.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.max.y), red); DTRRender_Line(context, DqnV2i_2f(bounds.min.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.max.y), red);
DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.max.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.min.y), red); DTRRender_Line(context, DqnV2i_2f(bounds.max.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.min.y), red);
DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.max.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.min.y), red); DTRRender_Line(context, DqnV2i_2f(bounds.max.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.min.y), red);
} }
// Draw Coordinate Basis // Draw Coordinate Basis
@ -743,9 +751,9 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderBuffer *const renderBuffer, const Dq
DqnV2 yAxis = DqnV2_2f(-xAxis.y, xAxis.x) * transform.scale.y; DqnV2 yAxis = DqnV2_2f(-xAxis.y, xAxis.x) * transform.scale.y;
DqnV4 coordSysColor = DqnV4_4f(0, 1, 1, 1); DqnV4 coordSysColor = DqnV4_4f(0, 1, 1, 1);
i32 axisLen = 50; i32 axisLen = 50;
DTRRender_Line(renderBuffer, DqnV2i_V2(origin), DTRRender_Line(context, DqnV2i_V2(origin),
DqnV2i_V2(origin) + DqnV2i_V2(xAxis * axisLen), coordSysColor); DqnV2i_V2(origin) + DqnV2i_V2(xAxis * axisLen), coordSysColor);
DTRRender_Line(renderBuffer, DqnV2i_V2(origin), DTRRender_Line(context, DqnV2i_V2(origin),
DqnV2i_V2(origin) + DqnV2i_V2(yAxis * axisLen), coordSysColor); DqnV2i_V2(origin) + DqnV2i_V2(yAxis * axisLen), coordSysColor);
} }
} }
@ -757,11 +765,40 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderBuffer *const renderBuffer, const Dq
for (i32 i = 0; i < pListSize; i++) for (i32 i = 0; i < pListSize; i++)
{ {
DqnV2 p = pList[i]; DqnV2 p = pList[i];
DTRRender_Rectangle(renderBuffer, p - DqnV2_1f(5), p + DqnV2_1f(5), colorList[i]); DTRRender_Rectangle(context, p - DqnV2_1f(5), p + DqnV2_1f(5), colorList[i]);
} }
} }
} }
FILE_SCOPE inline f32 GetCurrZDepth(DTRRenderContext context, i32 posX, i32 posY)
{
DTRRenderBuffer *renderBuffer = context.renderBuffer;
DQN_ASSERT(renderBuffer);
const u32 zBufferPitch = renderBuffer->width;
i32 zBufferIndex = posX + (posY * zBufferPitch);
DQN_ASSERT(zBufferIndex < (renderBuffer->width * renderBuffer->height));
context.api->LockAcquire(renderBuffer->renderLock);
f32 currZDepth = renderBuffer->zBuffer[zBufferIndex];
context.api->LockRelease(renderBuffer->renderLock);
return currZDepth;
}
FILE_SCOPE inline void SetCurrZDepth(DTRRenderContext context, i32 posX, i32 posY, f32 newZDepth)
{
DTRRenderBuffer *renderBuffer = context.renderBuffer;
DQN_ASSERT(renderBuffer);
const u32 zBufferPitch = renderBuffer->width;
i32 zBufferIndex = posX + (posY * zBufferPitch);
DQN_ASSERT(zBufferIndex < (renderBuffer->width * renderBuffer->height));
context.api->LockAcquire(renderBuffer->renderLock);
renderBuffer->zBuffer[zBufferIndex] = newZDepth;
context.api->LockRelease(renderBuffer->renderLock);
}
#define DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(type) \ #define DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(type) \
do \ do \
{ \ { \
@ -780,20 +817,18 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderBuffer *const renderBuffer, const Dq
DTRDebug_EndCycleCount(DTRDebugCycleCount_SIMD##type); \ DTRDebug_EndCycleCount(DTRDebugCycleCount_SIMD##type); \
} while (0) } while (0)
FILE_SCOPE void SIMDRasteriseTrianglePixel(DTRRenderBuffer *const renderBuffer, FILE_SCOPE void
const DTRBitmap *const texture, const i32 posX, SIMDRasteriseTrianglePixel(DTRRenderContext context, const DTRBitmap *const texture, const i32 posX,
const i32 posY, const i32 maxX, const DqnV2 uv1, const i32 posY, const i32 maxX, const DqnV2 uv1, const DqnV2 uv2SubUv1,
const DqnV2 uv2SubUv1, const DqnV2 uv3SubUv1, const DqnV2 uv3SubUv1, const __m128 simdColor, const __m128 triangleZ,
const __m128 simdColor, const __m128 triangleZ, const __m128 signedArea, const __m128 invSignedAreaParallelogram_4x,
const __m128 signedArea, const f32 preserveAlpha, const bool ignoreLight, const __m128 p1Light,
const __m128 invSignedAreaParallelogram_4x) const __m128 p2Light, const __m128 p3Light)
{ {
const __m128 ZERO_4X = _mm_set_ps1(0.0f); DTRRenderBuffer *const renderBuffer = context.renderBuffer;
const u32 IS_GREATER_MASK = 0xF; const __m128 ZERO_4X = _mm_set_ps1(0.0f);
const u32 zBufferPitch = renderBuffer->width; const u32 IS_GREATER_MASK = 0xF;
const u32 zBufferPitch = renderBuffer->width;
// TODO(doyle): Copy lighting work over. But not important since using this
// function causes performance problems.
// Rasterise buffer(X, Y) pixel // Rasterise buffer(X, Y) pixel
{ {
@ -803,32 +838,51 @@ FILE_SCOPE void SIMDRasteriseTrianglePixel(DTRRenderBuffer *const renderBuffer,
if ((isGreaterResult & IS_GREATER_MASK) == IS_GREATER_MASK && posX < maxX) if ((isGreaterResult & IS_GREATER_MASK) == IS_GREATER_MASK && posX < maxX)
{ {
DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel); DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel);
__m128 barycentric = _mm_mul_ps(signedArea, invSignedAreaParallelogram_4x);
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
i32 zBufferIndex = posX + (posY * zBufferPitch);
f32 pixelZValue =
((f32 *)&barycentricZ)[0] + ((f32 *)&barycentricZ)[1] + ((f32 *)&barycentricZ)[2];
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
if (pixelZValue > currZValue)
{ {
renderBuffer->zBuffer[zBufferIndex] = pixelZValue; __m128 barycentric = _mm_mul_ps(signedArea, invSignedAreaParallelogram_4x);
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
__m128 finalColor = simdColor; f32 pixelZDepth = ((f32 *)&barycentricZ)[0] + ((f32 *)&barycentricZ)[1] +
if (texture) ((f32 *)&barycentricZ)[2];
i32 zBufferIndex = posX + (posY * zBufferPitch);
if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex])
{ {
__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, renderBuffer->zBuffer[zBufferIndex] = pixelZDepth;
uv3SubUv1, barycentric); __m128 finalColor = simdColor;
finalColor = _mm_mul_ps(texSampledColor, simdColor); if (!ignoreLight)
{
__m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]);
__m128 barycentricB_4x = _mm_set_ps1(((f32 *)&barycentric)[1]);
__m128 barycentricC_4x = _mm_set_ps1(((f32 *)&barycentric)[2]);
__m128 barycentricLight1 = _mm_mul_ps(p1Light, barycentricA_4x);
__m128 barycentricLight2 = _mm_mul_ps(p2Light, barycentricB_4x);
__m128 barycentricLight3 = _mm_mul_ps(p3Light, barycentricC_4x);
__m128 light = _mm_add_ps(barycentricLight3,
_mm_add_ps(barycentricLight1, barycentricLight2));
finalColor = _mm_mul_ps(finalColor, light);
((f32 *)&finalColor)[3] = preserveAlpha;
}
if (texture)
{
__m128 texSampledColor = SIMDSampleTextureForTriangle(
texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
finalColor = _mm_mul_ps(texSampledColor, finalColor);
}
SIMDSetPixel(context, posX, posY, finalColor, ColorSpace_Linear);
} }
SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear);
} }
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel); DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel);
} }
} }
} }
FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1, const DqnV3 p2, FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const DqnV3 p2,
const DqnV3 p3, const DqnV2 uv1, const DqnV2 uv2, const DqnV2 uv3, const DqnV3 p3, const DqnV2 uv1, const DqnV2 uv2, const DqnV2 uv3,
const f32 lightIntensity1, const f32 lightIntensity2, const f32 lightIntensity1, const f32 lightIntensity2,
const f32 lightIntensity3, const bool ignoreLight, const f32 lightIntensity3, const bool ignoreLight,
@ -840,6 +894,8 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle); DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle);
DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Preamble); DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Preamble);
DTRRenderBuffer *const renderBuffer = context.renderBuffer;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Convert color // Convert color
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -864,16 +920,16 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Setup SIMD data // Setup SIMD data
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
const u32 NUM_X_PIXELS_TO_SIMD = 2; const u32 NUM_X_PIXELS_TO_SIMD = 1;
const u32 NUM_Y_PIXELS_TO_SIMD = 1; const u32 NUM_Y_PIXELS_TO_SIMD = 1;
// SignedArea: _mm_set_ps(unused, p3, p2, p1) ie 0=p1, 1=p1, 2=p3, 3=unused // SignedArea: _mm_set_ps(unused, p3, p2, p1) ie 0=p1, 1=p1, 2=p3, 3=unused
__m128 signedAreaPixel1; __m128 signedAreaPixel1 = _mm_set_ps1(0);
__m128 signedAreaPixel2; // __m128 signedAreaPixel2 = _mm_set_ps1(0);
__m128 signedAreaPixelDeltaX; __m128 signedAreaPixelDeltaX = _mm_set_ps1(0);
__m128 signedAreaPixelDeltaY; __m128 signedAreaPixelDeltaY = _mm_set_ps1(0);
__m128 invSignedAreaParallelogram_4x; __m128 invSignedAreaParallelogram_4x = _mm_set_ps1(0);
__m128 triangleZ = _mm_set_ps(0, p3.z, p2.z, p1.z); __m128 triangleZ = _mm_set_ps(0, p3.z, p2.z, p1.z);
{ {
@ -906,7 +962,7 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
signedAreaPixelDeltaY = _mm_set_ps(0, signedArea3DeltaY, signedArea2DeltaY, signedArea1DeltaY); signedAreaPixelDeltaY = _mm_set_ps(0, signedArea3DeltaY, signedArea2DeltaY, signedArea1DeltaY);
signedAreaPixel1 = _mm_set_ps(0, signedArea3Start, signedArea2Start, signedArea1Start); signedAreaPixel1 = _mm_set_ps(0, signedArea3Start, signedArea2Start, signedArea1Start);
signedAreaPixel2 = _mm_add_ps(signedAreaPixel1, signedAreaPixelDeltaX); // signedAreaPixel2 = _mm_add_ps(signedAreaPixel1, signedAreaPixelDeltaX);
// NOTE: Increase step size to the number of pixels rasterised with SIMD // NOTE: Increase step size to the number of pixels rasterised with SIMD
{ {
@ -922,13 +978,9 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
const DqnV2 uv2SubUv1 = uv2 - uv1; const DqnV2 uv2SubUv1 = uv2 - uv1;
const DqnV2 uv3SubUv1 = uv3 - uv1; const DqnV2 uv3SubUv1 = uv3 - uv1;
#define UNROLL_LOOP 1
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Preamble); DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Preamble);
#if UNROLL_LOOP
const u32 IS_GREATER_MASK = 0xF; const u32 IS_GREATER_MASK = 0xF;
const u32 zBufferPitch = renderBuffer->width; const u32 zBufferPitch = renderBuffer->width;
#endif
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Scan and Render // Scan and Render
@ -937,11 +989,10 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
for (i32 bufferY = min.y; bufferY < max.y; bufferY += NUM_Y_PIXELS_TO_SIMD) for (i32 bufferY = min.y; bufferY < max.y; bufferY += NUM_Y_PIXELS_TO_SIMD)
{ {
__m128 signedArea1 = signedAreaPixel1; __m128 signedArea1 = signedAreaPixel1;
__m128 signedArea2 = signedAreaPixel2; // __m128 signedArea2 = signedAreaPixel2;
for (i32 bufferX = min.x; bufferX < max.x; bufferX += NUM_X_PIXELS_TO_SIMD) for (i32 bufferX = min.x; bufferX < max.x; bufferX += NUM_X_PIXELS_TO_SIMD)
{ {
#if UNROLL_LOOP
// Rasterise buffer(X, Y) pixel // Rasterise buffer(X, Y) pixel
{ {
__m128 checkArea = signedArea1; __m128 checkArea = signedArea1;
@ -956,20 +1007,31 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
__m128 barycentric = _mm_mul_ps(checkArea, invSignedAreaParallelogram_4x); __m128 barycentric = _mm_mul_ps(checkArea, invSignedAreaParallelogram_4x);
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric); __m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
i32 zBufferIndex = posX + (posY * zBufferPitch); f32 pixelZDepth = ((f32 *)&barycentricZ)[0] +
f32 pixelZValue = ((f32 *)&barycentricZ)[0] +
((f32 *)&barycentricZ)[1] + ((f32 *)&barycentricZ)[1] +
((f32 *)&barycentricZ)[2]; ((f32 *)&barycentricZ)[2];
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
if (pixelZValue > currZValue) i32 zBufferIndex = posX + (posY * zBufferPitch);
if (context.multithread)
{
bool currLockValue;
do
{
currLockValue = (bool)context.api->AtomicCompareSwap(
(u32 *)&renderBuffer->pixelLockTable[zBufferIndex], (u32) true,
(u32) false);
} while (currLockValue != false);
}
if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex])
{ {
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
__m128 finalColor = simdColor; __m128 finalColor = simdColor;
renderBuffer->zBuffer[zBufferIndex] = pixelZDepth;
if (!ignoreLight) if (!ignoreLight)
{ {
__m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]); __m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]);
__m128 barycentricB_4x = _mm_set_ps1(((f32 *)&barycentric)[1]); __m128 barycentricB_4x = _mm_set_ps1(((f32 *)&barycentric)[1]);
__m128 barycentricC_4x = _mm_set_ps1(((f32 *)&barycentric)[2]); __m128 barycentricC_4x = _mm_set_ps1(((f32 *)&barycentric)[2]);
__m128 barycentricLight1 = _mm_mul_ps(p1Light, barycentricA_4x); __m128 barycentricLight1 = _mm_mul_ps(p1Light, barycentricA_4x);
__m128 barycentricLight2 = _mm_mul_ps(p2Light, barycentricB_4x); __m128 barycentricLight2 = _mm_mul_ps(p2Light, barycentricB_4x);
@ -979,91 +1041,34 @@ FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
_mm_add_ps(barycentricLight3, _mm_add_ps(barycentricLight3,
_mm_add_ps(barycentricLight1, barycentricLight2)); _mm_add_ps(barycentricLight1, barycentricLight2));
finalColor = _mm_mul_ps(finalColor, light); finalColor = _mm_mul_ps(finalColor, light);
((f32 *)&finalColor)[3] = preserveAlpha; ((f32 *)&finalColor)[3] = preserveAlpha;
} }
if (texture) if (texture)
{ {
__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, uv3SubUv1, barycentric); __m128 texSampledColor = SIMDSampleTextureForTriangle(
finalColor = _mm_mul_ps(texSampledColor, finalColor); texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
finalColor = _mm_mul_ps(texSampledColor, finalColor);
} }
SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear);
SIMDSetPixel(context, posX, posY, finalColor, ColorSpace_Linear);
} }
renderBuffer->pixelLockTable[zBufferIndex] = false;
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel); DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel);
} }
signedArea1 = _mm_add_ps(signedArea1, signedAreaPixelDeltaX); signedArea1 = _mm_add_ps(signedArea1, signedAreaPixelDeltaX);
} }
// Rasterise buffer(X + 1, Y) pixel
{
__m128 checkArea = signedArea2;
__m128 isGreater = _mm_cmpge_ps(checkArea, ZERO_4X);
i32 isGreaterResult = _mm_movemask_ps(isGreater);
i32 posX = bufferX + 1;
i32 posY = bufferY;
if ((isGreaterResult & IS_GREATER_MASK) == IS_GREATER_MASK && posX < max.x)
{
__m128 barycentric = _mm_mul_ps(checkArea, invSignedAreaParallelogram_4x);
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
i32 zBufferIndex = posX + (posY * zBufferPitch);
f32 pixelZValue = ((f32 *)&barycentricZ)[0] +
((f32 *)&barycentricZ)[1] +
((f32 *)&barycentricZ)[2];
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
if (pixelZValue > currZValue)
{
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
__m128 finalColor = simdColor;
if (!ignoreLight)
{
__m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]);
__m128 barycentricB_4x = _mm_set_ps1(((f32 *)&barycentric)[1]);
__m128 barycentricC_4x = _mm_set_ps1(((f32 *)&barycentric)[2]);
__m128 barycentricLight1 = _mm_mul_ps(p1Light, barycentricA_4x);
__m128 barycentricLight2 = _mm_mul_ps(p2Light, barycentricB_4x);
__m128 barycentricLight3 = _mm_mul_ps(p3Light, barycentricC_4x);
__m128 light =
_mm_add_ps(barycentricLight3,
_mm_add_ps(barycentricLight1, barycentricLight2));
finalColor = _mm_mul_ps(finalColor, light);
((f32 *)&finalColor)[3] = preserveAlpha;
}
if (texture)
{
__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
finalColor = _mm_mul_ps(texSampledColor, finalColor);
}
SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear);
}
}
signedArea2 = _mm_add_ps(signedArea2, signedAreaPixelDeltaX);
}
#else
SIMDRasteriseTrianglePixel(renderBuffer, texture, bufferX, bufferY, max.x, uv1, uv2SubUv1,
uv3SubUv1, simdColor, triangleZ, signedArea1,
invSignedAreaParallelogram_4x);
SIMDRasteriseTrianglePixel(renderBuffer, texture, bufferX + 1, bufferY, max.x, uv1, uv2SubUv1,
uv3SubUv1, simdColor, triangleZ, signedArea2,
invSignedAreaParallelogram_4x);
signedArea1 = _mm_add_ps(signedArea1, signedAreaPixelDeltaX);
signedArea2 = _mm_add_ps(signedArea2, signedAreaPixelDeltaX);
#endif
} }
signedAreaPixel1 = _mm_add_ps(signedAreaPixel1, signedAreaPixelDeltaY); signedAreaPixel1 = _mm_add_ps(signedAreaPixel1, signedAreaPixelDeltaY);
signedAreaPixel2 = _mm_add_ps(signedAreaPixel2, signedAreaPixelDeltaY); // signedAreaPixel2 = _mm_add_ps(signedAreaPixel2, signedAreaPixelDeltaY);
} }
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Rasterise); DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Rasterise);
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle); DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle);
} }
FILE_SCOPE void SlowTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1, const DqnV3 p2, FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const DqnV3 p2,
const DqnV3 p3, const DqnV2 uv1, const DqnV2 uv2, const DqnV2 uv3, const DqnV3 p3, const DqnV2 uv1, const DqnV2 uv2, const DqnV2 uv3,
const f32 lightIntensity1, const f32 lightIntensity2, const f32 lightIntensity1, const f32 lightIntensity2,
const f32 lightIntensity3, const bool ignoreLight, const f32 lightIntensity3, const bool ignoreLight,
@ -1071,7 +1076,6 @@ FILE_SCOPE void SlowTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
const DqnV2i max) const DqnV2i max)
{ {
DTR_DEBUG_EP_TIMED_FUNCTION(); DTR_DEBUG_EP_TIMED_FUNCTION();
#define DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(type) \ #define DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(type) \
do \ do \
{ \ { \
@ -1091,8 +1095,9 @@ FILE_SCOPE void SlowTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
} while (0) } while (0)
DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle); DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle);
DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Preamble); DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Preamble);
DTRRenderBuffer *renderBuffer = context.renderBuffer;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Convert Color // Convert Color
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -1154,14 +1159,23 @@ FILE_SCOPE void SlowTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
f32 barycentricC = signedArea3 * invSignedAreaParallelogram; f32 barycentricC = signedArea3 * invSignedAreaParallelogram;
i32 zBufferIndex = bufferX + (bufferY * zBufferPitch); i32 zBufferIndex = bufferX + (bufferY * zBufferPitch);
f32 pixelZValue = p1.z + (barycentricB * (p2SubP1.z)) + (barycentricC * (p3SubP1.z)); if (context.multithread)
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
DQN_ASSERT(zBufferIndex < (renderBuffer->width * renderBuffer->height));
if (pixelZValue > currZValue)
{ {
renderBuffer->zBuffer[zBufferIndex] = pixelZValue; bool currLockValue;
DqnV4 finalColor = color; do
{
currLockValue = (bool)context.api->AtomicCompareSwap(
(u32 *)&renderBuffer->pixelLockTable[zBufferIndex], (u32) true,
(u32) false);
} while (currLockValue != false);
}
f32 pixelZDepth =
p1.z + (barycentricB * (p2SubP1.z)) + (barycentricC * (p3SubP1.z));
if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex])
{
DqnV4 finalColor = color;
renderBuffer->zBuffer[zBufferIndex] = pixelZDepth;
if (!ignoreLight) if (!ignoreLight)
{ {
@ -1202,8 +1216,9 @@ FILE_SCOPE void SlowTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1
finalColor *= color1; finalColor *= color1;
} }
SetPixel(renderBuffer, bufferX, bufferY, finalColor, ColorSpace_Linear); SetPixel(context, bufferX, bufferY, finalColor, ColorSpace_Linear);
} }
renderBuffer->pixelLockTable[zBufferIndex] = false;
DEBUG_SLOW_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel); DEBUG_SLOW_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel);
} }
@ -1247,11 +1262,14 @@ DqnMat4 GLViewport(f32 x, f32 y, f32 width, f32 height)
return result; return result;
} }
FILE_SCOPE void TexturedTriangleInternal(DTRRenderBuffer *const renderBuffer, FILE_SCOPE void
RenderLightInternal lighting, DqnV3 p1, DqnV3 p2, DqnV3 p3, TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting, DqnV3 p1, DqnV3 p2,
DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture,
DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()) DqnV4 color,
const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform())
{ {
DTRRenderBuffer *renderBuffer = context.renderBuffer;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Transform vertexes p1, p2, p3 inplace // Transform vertexes p1, p2, p3 inplace
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -1308,12 +1326,12 @@ FILE_SCOPE void TexturedTriangleInternal(DTRRenderBuffer *const renderBuffer,
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
if (globalDTRPlatformFlags.canUseSSE2) if (globalDTRPlatformFlags.canUseSSE2)
{ {
SIMDTriangle(renderBuffer, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2, SIMDTriangle(context, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2,
lightIntensity3, ignoreLight, texture, color, min, max); lightIntensity3, ignoreLight, texture, color, min, max);
} }
else else
{ {
SlowTriangle(renderBuffer, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2, SlowTriangle(context, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2,
lightIntensity3, ignoreLight, texture, color, min, max); lightIntensity3, ignoreLight, texture, color, min, max);
} }
@ -1326,7 +1344,7 @@ FILE_SCOPE void TexturedTriangleInternal(DTRRenderBuffer *const renderBuffer,
bool drawBasis = false; bool drawBasis = false;
bool drawVertexMarkers = false; bool drawVertexMarkers = false;
DebugRenderMarkers(renderBuffer, pList, DQN_ARRAY_COUNT(pList), transform, drawBoundingBox, DebugRenderMarkers(context, pList, DQN_ARRAY_COUNT(pList), transform, drawBoundingBox,
drawBasis, drawVertexMarkers); drawBasis, drawVertexMarkers);
} }
} }
@ -1337,20 +1355,51 @@ FILE_SCOPE RenderLightInternal NullRenderLightInternal()
return result; return result;
} }
void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, void DTRRender_TexturedTriangle(DTRRenderContext context,
DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3,
DTRBitmap *const texture, DqnV4 color, DTRBitmap *const texture, DqnV4 color,
const DTRRenderTransform transform) const DTRRenderTransform transform)
{ {
TexturedTriangleInternal(renderBuffer, NullRenderLightInternal(), p1, p2, p3, uv1, uv2, uv3, texture, TexturedTriangleInternal(context, NullRenderLightInternal(), p1, p2, p3, uv1, uv2, uv3, texture,
color, transform); color, transform);
} }
void DTRRender_Mesh(DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh, typedef struct RenderMeshJob
DTRRenderLight lighting, const DqnV3 pos,
const DTRRenderTransform transform)
{ {
if (!mesh) return; DTRRenderContext context;
DTRBitmap *tex;
RenderLightInternal lighting;
DqnV3 v1;
DqnV3 v2;
DqnV3 v3;
DqnV2 uv1;
DqnV2 uv2;
DqnV2 uv3;
DqnV4 color;
} RenderMeshJob;
void MultiThreadedRenderMesh(PlatformJobQueue *const queue, void *const userData)
{
if (!queue || !userData)
{
DQN_ASSERT(DQN_INVALID_CODE_PATH);
return;
}
RenderMeshJob *job = (RenderMeshJob *)userData;
TexturedTriangleInternal(job->context, job->lighting, job->v1, job->v2, job->v3, job->uv1,
job->uv2, job->uv3, job->tex, job->color);
}
void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue, DTRMesh *const mesh,
DTRRenderLight lighting, const DqnV3 pos, const DTRRenderTransform transform)
{
DqnMemStack *const tempStack = context.tempStack;
DTRRenderBuffer *const renderBuffer = context.renderBuffer;
PlatformAPI *const api = context.api;
if (!mesh || !renderBuffer || !tempStack || !api || !jobQueue) return;
DqnMat4 viewPModelViewProjection = {}; DqnMat4 viewPModelViewProjection = {};
{ {
@ -1452,7 +1501,8 @@ void DTRRender_Mesh(DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh,
DqnV2 uv2 = mesh->texUV[uv2Index].xy; DqnV2 uv2 = mesh->texUV[uv2Index].xy;
DqnV2 uv3 = mesh->texUV[uv3Index].xy; DqnV2 uv3 = mesh->texUV[uv3Index].xy;
DqnV4 color = lighting.color; DqnV4 color = lighting.color;
RenderLightInternal lightingInternal = {}; RenderLightInternal lightingInternal = {};
lightingInternal.mode = lighting.mode; lightingInternal.mode = lighting.mode;
lightingInternal.vector = lighting.vector; lightingInternal.vector = lighting.vector;
@ -1462,43 +1512,92 @@ void DTRRender_Mesh(DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh,
lightingInternal.numNormals = 3; lightingInternal.numNormals = 3;
bool DEBUG_NO_TEX = false; bool DEBUG_NO_TEX = false;
if (DTR_DEBUG && DEBUG_NO_TEX) if (context.multithread)
{ {
TexturedTriangleInternal(renderBuffer, lightingInternal, v1.xyz, v2.xyz, v3.xyz, uv1, RenderMeshJob *jobData = (RenderMeshJob *)DqnMemStack_Push(tempStack, sizeof(*jobData));
uv2, uv3, NULL, color); if (jobData)
{
jobData->v1 = v1.xyz;
jobData->v2 = v2.xyz;
jobData->v3 = v3.xyz;
jobData->uv1 = uv1;
jobData->uv2 = uv2;
jobData->uv3 = uv3;
jobData->color = color;
jobData->lighting = lightingInternal;
jobData->context = context;
if (DTR_DEBUG && DEBUG_NO_TEX)
{
jobData->tex = NULL;
}
else
{
jobData->tex = &mesh->tex;
}
PlatformJob renderJob = {};
renderJob.callback = MultiThreadedRenderMesh;
renderJob.userData = jobData;
while (!api->QueueAddJob(jobQueue, renderJob))
{
api->QueueTryExecuteNextJob(jobQueue);
}
}
else
{
// TODO(doyle): Allocation error
DQN_ASSERT(DQN_INVALID_CODE_PATH);
}
} }
else else
{ {
TexturedTriangleInternal(renderBuffer, lightingInternal, v1.xyz, v2.xyz, v3.xyz, uv1, if (DTR_DEBUG && DEBUG_NO_TEX)
uv2, uv3, &mesh->tex, color); {
TexturedTriangleInternal(context, lightingInternal, v1.xyz, v2.xyz, v3.xyz,
uv1, uv2, uv3, NULL, color);
}
else
{
TexturedTriangleInternal(context, lightingInternal, v1.xyz, v2.xyz, v3.xyz,
uv1, uv2, uv3, &mesh->tex, color);
}
} }
bool DEBUG_WIREFRAME = false; bool DEBUG_WIREFRAME = false;
if (DTR_DEBUG && DEBUG_WIREFRAME) if (DTR_DEBUG && DEBUG_WIREFRAME)
{ {
DqnV4 wireColor = DqnV4_4f(1.0f, 1.0f, 1.0f, 0.01f); DqnV4 wireColor = DqnV4_4f(1.0f, 1.0f, 1.0f, 0.01f);
DTRRender_Line(renderBuffer, DqnV2i_V2(v1.xy), DqnV2i_V2(v2.xy), DTRRender_Line(context, DqnV2i_V2(v1.xy), DqnV2i_V2(v2.xy), wireColor);
wireColor); DTRRender_Line(context, DqnV2i_V2(v2.xy), DqnV2i_V2(v3.xy), wireColor);
DTRRender_Line(renderBuffer, DqnV2i_V2(v2.xy), DqnV2i_V2(v3.xy), DTRRender_Line(context, DqnV2i_V2(v3.xy), DqnV2i_V2(v1.xy), wireColor);
wireColor);
DTRRender_Line(renderBuffer, DqnV2i_V2(v3.xy), DqnV2i_V2(v1.xy),
wireColor);
} }
} }
if (context.multithread)
{
// NOTE(doyle): Complete remaining jobs and wait until all jobs finished
// before leaving function.
while (api->QueueTryExecuteNextJob(jobQueue) || !api->QueueAllJobsComplete(jobQueue))
;
}
} }
void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, void DTRRender_Triangle(DTRRenderContext context, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color,
DqnV4 color, const DTRRenderTransform transform) const DTRRenderTransform transform)
{ {
const DqnV2 NO_UV = {}; const DqnV2 NO_UV = {};
DTRBitmap *const NO_TEX = NULL; DTRBitmap *const NO_TEX = NULL;
TexturedTriangleInternal(renderBuffer, NullRenderLightInternal(), p1, p2, p3, NO_UV, NO_UV, TexturedTriangleInternal(context, NullRenderLightInternal(), p1, p2, p3, NO_UV, NO_UV,
NO_UV, NO_TEX, color, transform); NO_UV, NO_TEX, color, transform);
} }
void DTRRender_Bitmap(DTRRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, void DTRRender_Bitmap(DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 pos,
const DTRRenderTransform transform, DqnV4 color) const DTRRenderTransform transform, DqnV4 color)
{ {
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!bitmap || !bitmap->memory || !renderBuffer) return; if (!bitmap || !bitmap->memory || !renderBuffer) return;
DTR_DEBUG_EP_TIMED_FUNCTION(); DTR_DEBUG_EP_TIMED_FUNCTION();
@ -1672,7 +1771,7 @@ void DTRRender_Bitmap(DTRRenderBuffer *const renderBuffer, DTRBitmap *const bitm
blend.g *= color.g; blend.g *= color.g;
blend.b *= color.b; blend.b *= color.b;
SetPixel(renderBuffer, bufferX, bufferY, blend, ColorSpace_Linear); SetPixel(context, bufferX, bufferY, blend, ColorSpace_Linear);
} }
} }
} }
@ -1686,14 +1785,14 @@ void DTRRender_Bitmap(DTRRenderBuffer *const renderBuffer, DTRBitmap *const bitm
bool drawBasis = true; bool drawBasis = true;
bool drawVertexMarkers = true; bool drawVertexMarkers = true;
DebugRenderMarkers(renderBuffer, pList, RECT_PLIST_SIZE, transform, drawBoundingBox, DebugRenderMarkers(context, pList, RECT_PLIST_SIZE, transform, drawBoundingBox,
drawBasis, drawVertexMarkers); drawBasis, drawVertexMarkers);
} }
} }
void DTRRender_Clear(DTRRenderBuffer *const renderBuffer, void DTRRender_Clear(DTRRenderContext context, DqnV3 color)
DqnV3 color)
{ {
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!renderBuffer) return; if (!renderBuffer) return;
DQN_ASSERT(color.r >= 0.0f && color.r <= 1.0f); DQN_ASSERT(color.r >= 0.0f && color.r <= 1.0f);
@ -1714,3 +1813,4 @@ void DTRRender_Clear(DTRRenderBuffer *const renderBuffer,
} }
} }
} }

View File

@ -2,10 +2,10 @@
#define DTRENDERER_RENDER_H #define DTRENDERER_RENDER_H
#include "dqn.h" #include "dqn.h"
#include "DTRendererPlatform.h"
#define DTRRENDER_INV_255 1.0f/255.0f #define DTRRENDER_INV_255 1.0f/255.0f
typedef struct DTRRenderBuffer DTRRenderBuffer;
typedef struct DTRBitmap DTRBitmap; typedef struct DTRBitmap DTRBitmap;
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -16,9 +16,11 @@ typedef struct DTRRenderBuffer
i32 width; i32 width;
i32 height; i32 height;
i32 bytesPerPixel; i32 bytesPerPixel;
PlatformLock *renderLock;
volatile u8 *memory; // Format: XX RR GG BB, and has (width * height * bytesPerPixels) elements
volatile f32 *zBuffer; // zBuffer has (width * height) elements
u8 *memory; // Format: XX RR GG BB, and has (width * height * bytesPerPixels) elements volatile bool *pixelLockTable; // has (width * height) elements
f32 *zBuffer; // zBuffer has (width * height) elements
} DTRRenderBuffer; } DTRRenderBuffer;
@ -74,15 +76,25 @@ typedef struct DTRRenderLight
DqnV4 color; DqnV4 color;
} DTRRenderLight; } DTRRenderLight;
typedef struct DTRRenderContext
{
DTRRenderBuffer *renderBuffer;
DqnMemStack *tempStack;
PlatformAPI *api;
PlatformJobQueue *jobQueue;
bool multithread;
} DTRRenderContext;
// NOTE: All colors should be in the range of [0->1] where DqnV4 is a struct with 4 floats, rgba // NOTE: All colors should be in the range of [0->1] where DqnV4 is a struct with 4 floats, rgba
// Leaving len = -1 for text will make the system use strlen to determine len. // Leaving len = -1 for text will make the system use strlen to determine len.
void DTRRender_Text (DTRRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1); void DTRRender_Text (DTRRenderContext context, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1);
void DTRRender_Line (DTRRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color); void DTRRender_Line (DTRRenderContext context, DqnV2i a, DqnV2i b, DqnV4 color);
void DTRRender_Rectangle (DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform()); void DTRRender_Rectangle (DTRRenderContext context, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform());
void DTRRender_Mesh (DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh, DTRRenderLight lighting, const DqnV3 pos, const DTRRenderTransform transform); void DTRRender_Mesh (DTRRenderContext context, PlatformJobQueue *const jobQueue, DTRMesh *const mesh, DTRRenderLight lighting, const DqnV3 pos, const DTRRenderTransform transform);
void DTRRender_Triangle (DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()); void DTRRender_Triangle (DTRRenderContext context, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform());
void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()); void DTRRender_TexturedTriangle(DTRRenderContext context, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform());
void DTRRender_Bitmap (DTRRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform = DTRRender_DefaultTransform(), DqnV4 color = DqnV4_4f(1, 1, 1, 1)); void DTRRender_Bitmap (DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform = DTRRender_DefaultTransform(), DqnV4 color = DqnV4_4f(1, 1, 1, 1));
void DTRRender_Clear (DTRRenderBuffer *const renderBuffer, DqnV3 color); void DTRRender_Clear (DTRRenderContext context, DqnV3 color);
#endif #endif

View File

@ -1,22 +1,161 @@
#include "DTRenderer.h"
#include "DTRendererPlatform.h"
#define DQN_IMPLEMENTATION
#define DQN_WIN32_IMPLEMENTATION
#include "dqn.h"
#define UNICODE #define UNICODE
#define _UNICODE #define _UNICODE
const char *const DLL_NAME = "dtrenderer.dll"; #include "DTRenderer.h"
const char *const DLL_TMP_NAME = "dtrenderer_temp.dll"; #include "DTRendererPlatform.h"
#define DQN_WIN32_IMPLEMENTATION
#define DQN_IMPLEMENTATION
#include "dqn.h"
#include <Windows.h>
#include <Windowsx.h> // For GET_X|Y_LPARAM(), mouse input
#include <Psapi.h> // For win32 GetProcessMemoryInfo()
FILE_SCOPE PlatformMemory globalPlatformMemory;
FILE_SCOPE bool globalRunning;
void Platform_DieGracefully() { globalRunning = false; }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Platform API Implementation // Platform Atomics
////////////////////////////////////////////////////////////////////////////////
u32 Platform_AtomicCompareSwap(u32 volatile *dest, u32 swapVal, u32 compareVal)
{
// TODO(doyle): Compile time assert
DQN_ASSERT(sizeof(LONG) == sizeof(u32));
u32 result =
(u32)InterlockedCompareExchange((LONG volatile *)dest, (LONG)swapVal, (LONG)compareVal);
return result;
}
////////////////////////////////////////////////////////////////////////////////
// Platform Mutex/Lock
////////////////////////////////////////////////////////////////////////////////
typedef struct PlatformLock
{
DqnLock dqnLock;
} PlatformLock;
PlatformLock *Platform_LockInit(DqnMemStack *const stack)
{
PlatformLock *result = (PlatformLock *)DqnMemStack_Push(stack, sizeof(PlatformLock));
if (result)
{
if (!DqnLock_Init(&result->dqnLock))
{
DqnMemStack_Pop(stack, result, sizeof(PlatformLock));
return NULL;
}
else
{
return result;
}
}
return NULL;
}
void Platform_LockAcquire(PlatformLock *const lock) { DqnLock_Acquire(&lock->dqnLock); }
void Platform_LockRelease(PlatformLock *const lock) { DqnLock_Release(&lock->dqnLock); }
void Platform_LockDelete (PlatformLock *const lock) { DqnLock_Delete(&lock->dqnLock); }
////////////////////////////////////////////////////////////////////////////////
// Platform Multi Threading
////////////////////////////////////////////////////////////////////////////////
struct PlatformJobQueue
{
PlatformJob *volatile jobList;
LONG size;
// NOTE: Modified by main+worker threads
LONG volatile jobToExecuteIndex;
HANDLE volatile win32Semaphore;
LONG volatile numJobsToComplete;
// NOTE: Modified by main thread ONLY
LONG volatile jobInsertIndex;
};
bool Platform_QueueAddJob(PlatformJobQueue *const queue, const PlatformJob job)
{
LONG newJobInsertIndex = (queue->jobInsertIndex + 1) % queue->size;
if (newJobInsertIndex == queue->jobToExecuteIndex) return false;
queue->jobList[queue->jobInsertIndex] = job;
InterlockedIncrement(&queue->numJobsToComplete);
ReleaseSemaphore(queue->win32Semaphore, 1, NULL);
queue->jobInsertIndex = newJobInsertIndex;
return true;
}
bool Platform_QueueTryExecuteNextJob(PlatformJobQueue *const queue)
{
LONG originalJobToExecute = queue->jobToExecuteIndex;
if (originalJobToExecute != queue->jobInsertIndex)
{
LONG newJobIndexForNextThread = (originalJobToExecute + 1) % queue->size;
LONG index = InterlockedCompareExchange(&queue->jobToExecuteIndex, newJobIndexForNextThread,
originalJobToExecute);
// NOTE: If we weren't successful at the interlock, another thread has
// taken the work and we can't know if there's more work or not. So
// irrespective of that result, return true to let the thread check
// again for more work.
if (index == originalJobToExecute)
{
PlatformJob job = queue->jobList[index];
job.callback(queue, job.userData);
InterlockedDecrement(&queue->numJobsToComplete);
}
return true;
}
return false;
}
bool Platform_QueueAllJobsComplete(PlatformJobQueue *const queue)
{
bool result = (queue->numJobsToComplete == 0);
return result;
}
FILE_SCOPE u32 volatile globalDebugCounter;
FILE_SCOPE bool volatile globalDebugCounterMemoize[2048];
FILE_SCOPE PlatformLock globalDebugLock;
FILE_SCOPE void DebugWin32IncrementCounter(PlatformJobQueue *const queue, void *const userData)
{
Platform_LockAcquire(&globalDebugLock);
DQN_ASSERT(!globalDebugCounterMemoize[globalDebugCounter]);
globalDebugCounterMemoize[globalDebugCounter] = true;
globalDebugCounter++;
u32 number = globalDebugCounter;
Platform_LockRelease(&globalDebugLock);
DqnWin32_OutputDebugString("Thread %d: Incrementing Number: %d\n", GetCurrentThreadId(),
number);
}
DWORD WINAPI Win32ThreadCallback(void *lpParameter)
{
PlatformJobQueue *queue = (PlatformJobQueue *)lpParameter;
for (;;)
{
if (!Platform_QueueTryExecuteNextJob(queue))
{
WaitForSingleObjectEx(queue->win32Semaphore, INFINITE, false);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// Platform I/O
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
FILE_SCOPE inline PlatformFile DqnFileToPlatformFileInternal(const DqnFile file) FILE_SCOPE inline PlatformFile DqnFileToPlatformFileInternal(const DqnFile file)
{ {
PlatformFile result = {}; PlatformFile result = {};
result.handle = file.handle; result.handle = file.handle;
result.size = file.size; result.size = file.size;
result.permissionFlags = file.permissionFlags; result.permissionFlags = file.permissionFlags;
@ -37,7 +176,7 @@ FILE_SCOPE inline DqnFile PlatformFileToDqnFileInternal(const PlatformFile file)
void Platform_Print(const char *const string) void Platform_Print(const char *const string)
{ {
if (!string) return; if (!string) return;
OutputDebugString(string); OutputDebugStringA(string);
} }
bool Platform_FileOpen(const char *const path, PlatformFile *const file, const u32 permissionFlags, bool Platform_FileOpen(const char *const path, PlatformFile *const file, const u32 permissionFlags,
@ -68,7 +207,7 @@ size_t Platform_FileRead(PlatformFile *const file, u8 *const buf,
if (!file || !buf) return 0; if (!file || !buf) return 0;
DqnFile dqnFile = PlatformFileToDqnFileInternal(*file); DqnFile dqnFile = PlatformFileToDqnFileInternal(*file);
size_t numBytesRead = DqnFile_Read(dqnFile, buf, bytesToRead); size_t numBytesRead = DqnFile_Read(&dqnFile, buf, bytesToRead);
return numBytesRead; return numBytesRead;
} }
@ -95,9 +234,9 @@ void Platform_FileClose(PlatformFile *const file)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Win32 Layer // Win32 Layer
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#include <Windows.h> const char *const DLL_NAME = "dtrenderer.dll";
#include <Windowsx.h> // For GET_X|Y_LPARAM(), mouse input const char *const DLL_TMP_NAME = "dtrenderer_temp.dll";
#include <Psapi.h> // For win32 GetProcessMemoryInfo()
typedef struct Win32RenderBitmap typedef struct Win32RenderBitmap
{ {
BITMAPINFO info; BITMAPINFO info;
@ -109,8 +248,6 @@ typedef struct Win32RenderBitmap
} Win32RenderBitmap; } Win32RenderBitmap;
FILE_SCOPE Win32RenderBitmap globalRenderBitmap; FILE_SCOPE Win32RenderBitmap globalRenderBitmap;
FILE_SCOPE PlatformMemory globalPlatformMemory;
FILE_SCOPE bool globalRunning;
typedef struct Win32ExternalCode typedef struct Win32ExternalCode
{ {
@ -150,7 +287,7 @@ FILETIME Win32GetLastWriteTime(const char *const srcName)
{ {
FILETIME lastWriteTime = {}; FILETIME lastWriteTime = {};
WIN32_FILE_ATTRIBUTE_DATA attribData = {}; WIN32_FILE_ATTRIBUTE_DATA attribData = {};
if (GetFileAttributesEx(srcName, GetFileExInfoStandard, &attribData) != 0) if (GetFileAttributesExA(srcName, GetFileExInfoStandard, &attribData) != 0)
{ {
lastWriteTime = attribData.ftLastWriteTime; lastWriteTime = attribData.ftLastWriteTime;
} }
@ -164,7 +301,7 @@ FILE_SCOPE Win32ExternalCode Win32LoadExternalDLL(const char *const srcPath,
{ {
Win32ExternalCode result = {}; Win32ExternalCode result = {};
result.lastWriteTime = lastWriteTime; result.lastWriteTime = lastWriteTime;
CopyFile(srcPath, tmpPath, false); CopyFileA(srcPath, tmpPath, false);
DTR_UpdateFunction *updateFunction = NULL; DTR_UpdateFunction *updateFunction = NULL;
result.dll = LoadLibraryA(tmpPath); result.dll = LoadLibraryA(tmpPath);
@ -195,10 +332,10 @@ FILE_SCOPE void Win32CreateMenu(HWND window)
HMENU menuBar = CreateMenu(); HMENU menuBar = CreateMenu();
{ // File Menu { // File Menu
HMENU menu = CreatePopupMenu(); HMENU menu = CreatePopupMenu();
AppendMenu(menuBar, MF_STRING | MF_POPUP, (UINT_PTR)menu, "File"); AppendMenuA(menuBar, MF_STRING | MF_POPUP, (UINT_PTR)menu, "File");
AppendMenu(menu, MF_STRING, Win32Menu_FileOpen, "Open"); AppendMenuA(menu, MF_STRING, Win32Menu_FileOpen, "Open");
AppendMenu(menu, MF_STRING, Win32Menu_FileFlushMemory, "Flush Memory"); AppendMenuA(menu, MF_STRING, Win32Menu_FileFlushMemory, "Flush Memory");
AppendMenu(menu, MF_STRING, Win32Menu_FileExit, "Exit"); AppendMenuA(menu, MF_STRING, Win32Menu_FileExit, "Exit");
} }
SetMenu(window, menuBar); SetMenu(window, menuBar);
} }
@ -412,55 +549,25 @@ FILE_SCOPE void Win32ProcessMessages(HWND window, PlatformInput *input)
} }
} }
// Return the index of the last slash int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd)
i32 Win32GetModuleDirectory(char *const buf, const u32 bufLen)
{ {
if (!buf || bufLen == 0) return 0;
u32 copiedLen = GetModuleFileName(NULL, buf, bufLen);
if (copiedLen == bufLen)
{
DQN_WIN32_ERROR_BOX(
"GetModuleFileName() buffer maxed: Len of copied text is len "
"of supplied buffer.",
NULL);
DQN_ASSERT(DQN_INVALID_CODE_PATH);
}
// NOTE: Should always work if GetModuleFileName works and we're running an
// executable.
i32 lastSlashIndex = 0;
for (i32 i = copiedLen; i > 0; i--)
{
if (buf[i] == '\\')
{
lastSlashIndex = i;
break;
}
}
return lastSlashIndex;
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nShowCmd)
{
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Initialise Win32 Window // Initialise Win32 Window
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
WNDCLASSEXW wc = WNDCLASSEXW wc = {
{ sizeof(WNDCLASSEX),
sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
CS_HREDRAW | CS_VREDRAW | CS_OWNDC, Win32MainProcCallback,
Win32MainProcCallback, 0, // int cbClsExtra
0, // int cbClsExtra 0, // int cbWndExtra
0, // int cbWndExtra hInstance,
hInstance, LoadIcon(NULL, IDI_APPLICATION),
LoadIcon(NULL, IDI_APPLICATION), LoadCursor(NULL, IDC_ARROW),
LoadCursor(NULL, IDC_ARROW), GetSysColorBrush(COLOR_3DFACE),
GetSysColorBrush(COLOR_3DFACE), L"", // LPCTSTR lpszMenuName
L"", // LPCTSTR lpszMenuName L"DRendererClass",
L"DRendererClass", NULL, // HICON hIconSm
NULL, // HICON hIconSm
}; };
if (!RegisterClassExW(&wc)) if (!RegisterClassExW(&wc))
@ -507,7 +614,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
globalRenderBitmap.width = header.biWidth; globalRenderBitmap.width = header.biWidth;
globalRenderBitmap.height = header.biHeight; globalRenderBitmap.height = header.biHeight;
globalRenderBitmap.bytesPerPixel = header.biBitCount / 8; globalRenderBitmap.bytesPerPixel = header.biBitCount / 8;
DQN_ASSERT(globalRenderBitmap.bytesPerPixel >= 1); if (!DQN_ASSERT(globalRenderBitmap.bytesPerPixel >= 1)) return -1;
HDC deviceContext = GetDC(mainWindow); HDC deviceContext = GetDC(mainWindow);
globalRenderBitmap.handle = CreateDIBSection( globalRenderBitmap.handle = CreateDIBSection(
@ -530,39 +637,130 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
char dllTmpPath[MAX_PATH] = {}; char dllTmpPath[MAX_PATH] = {};
{ {
char exeDir[MAX_PATH] = {}; char exeDir[MAX_PATH] = {};
i32 lastSlashIndex = i32 lastSlashIndex = DqnWin32_GetEXEDirectory(exeDir, DQN_ARRAY_COUNT(exeDir));
Win32GetModuleDirectory(exeDir, DQN_ARRAY_COUNT(exeDir)); if (DQN_ASSERT_MSG(lastSlashIndex != -1, "Not enough space in buffer for exe path"))
DQN_ASSERT(lastSlashIndex + 1 < DQN_ARRAY_COUNT(exeDir)); {
exeDir[lastSlashIndex + 1] = 0;
u32 dllNumCopied = Dqn_sprintf(dllPath, "%s%s", exeDir, DLL_NAME);
u32 dllTmpNumCopied = Dqn_sprintf(dllTmpPath, "%s%s", exeDir, DLL_TMP_NAME);
exeDir[lastSlashIndex + 1] = 0; if (!DQN_ASSERT_MSG((dllNumCopied < DQN_ARRAY_COUNT(dllPath)) &&
u32 numCopied = Dqn_sprintf(dllPath, "%s%s", exeDir, DLL_NAME); (dllTmpNumCopied < DQN_ARRAY_COUNT(dllPath)),
DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllPath)); "Out of space to form DLL path"))
{
numCopied = Platform_DieGracefully();
Dqn_sprintf(dllTmpPath, "%s%s", exeDir, DLL_TMP_NAME); }
DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllTmpPath)); }
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Platform Data Pre-amble // Platform Data Pre-amble
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.mainStack, DQN_MEGABYTE(4), true, 4) && bool memoryInitResult =
DqnMemStack_Init(&globalPlatformMemory.tempStack, DQN_MEGABYTE(4), true, 4) && DqnMemStack_Init(&globalPlatformMemory.mainStack, DQN_MEGABYTE(4), true, 4) |
DqnMemStack_Init(&globalPlatformMemory.assetStack, DQN_MEGABYTE(4), true, 4) DqnMemStack_Init(&globalPlatformMemory.tempStack, DQN_MEGABYTE(4), true, 4) |
); DqnMemStack_Init(&globalPlatformMemory.assetStack, DQN_MEGABYTE(4), true, 4);
if (!DQN_ASSERT_MSG(memoryInitResult, "Unable to allocate DTRenderer globalPlatformMemory stacks"))
{
Platform_DieGracefully();
}
PlatformAPI platformAPI = {}; PlatformAPI platformAPI = {};
platformAPI.FileOpen = Platform_FileOpen; platformAPI.DieGracefully = Platform_DieGracefully;
platformAPI.FileRead = Platform_FileRead;
platformAPI.FileWrite = Platform_FileWrite; platformAPI.FileOpen = Platform_FileOpen;
platformAPI.FileClose = Platform_FileClose; platformAPI.FileRead = Platform_FileRead;
platformAPI.Print = Platform_Print; platformAPI.FileWrite = Platform_FileWrite;
platformAPI.FileClose = Platform_FileClose;
platformAPI.Print = Platform_Print;
platformAPI.QueueAddJob = Platform_QueueAddJob;
platformAPI.QueueTryExecuteNextJob = Platform_QueueTryExecuteNextJob;
platformAPI.QueueAllJobsComplete = Platform_QueueAllJobsComplete;
platformAPI.AtomicCompareSwap = Platform_AtomicCompareSwap;
platformAPI.LockInit = Platform_LockInit;
platformAPI.LockAcquire = Platform_LockAcquire;
platformAPI.LockRelease = Platform_LockRelease;
platformAPI.LockDelete = Platform_LockDelete;
PlatformJobQueue jobQueue = {};
PlatformInput platformInput = {}; PlatformInput platformInput = {};
platformInput.api = platformAPI; platformInput.api = platformAPI;
platformInput.jobQueue = &jobQueue;
platformInput.flags.canUseSSE2 = IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE); platformInput.flags.canUseSSE2 = IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
platformInput.flags.canUseRdtsc = IsProcessorFeaturePresent(PF_RDTSC_INSTRUCTION_AVAILABLE); platformInput.flags.canUseRdtsc = IsProcessorFeaturePresent(PF_RDTSC_INSTRUCTION_AVAILABLE);
// Threading
PlatformJob jobQueueMemory[512] = {};
{
DqnMemStackTempRegion memRegion;
if (!DQN_ASSERT(DqnMemStackTempRegion_Begin(&memRegion, &globalPlatformMemory.tempStack)))
Platform_DieGracefully();
////////////////////////////////////////////////////////////////////////
// Query CPU Cores
////////////////////////////////////////////////////////////////////////
i32 numCores, numThreadsPerCore;
DqnWin32_GetNumThreadsAndCores(&numCores, &numThreadsPerCore);
////////////////////////////////////////////////////////////////////////
// Threading
////////////////////////////////////////////////////////////////////////
jobQueue.jobList = jobQueueMemory;
jobQueue.size = DQN_ARRAY_COUNT(jobQueueMemory);
// NOTE: InterlockedIncrement requires things to be on 32bit boundaries.
DQN_ASSERT(((size_t)&jobQueue.jobToExecuteIndex) % 4 == 0);
// NOTE: (numCores - 1), 1 core is already exclusively for main thread
i32 availableThreads = (numCores - 1) * numThreadsPerCore;
if (availableThreads <= 0) availableThreads = 1;
jobQueue.win32Semaphore = CreateSemaphore(NULL, 0, availableThreads, NULL);
if (jobQueue.win32Semaphore)
{
// Create threads
for (i32 i = 0; i < availableThreads; i++)
{
const i32 USE_DEFAULT_STACK_SIZE = 0;
void *threadParam = &jobQueue;
HANDLE handle = CreateThread(NULL, USE_DEFAULT_STACK_SIZE, Win32ThreadCallback,
threadParam, 0, NULL);
CloseHandle(handle);
}
#if 1
DQN_ASSERT_HARD(DqnLock_Init(&globalDebugLock.dqnLock));
for (i32 i = 0; i < DQN_ARRAY_COUNT(globalDebugCounterMemoize); i++)
{
PlatformJob job = {};
job.callback = DebugWin32IncrementCounter;
while (!Platform_QueueAddJob(&jobQueue, job))
{
Platform_QueueTryExecuteNextJob(&jobQueue);
}
}
while (Platform_QueueTryExecuteNextJob(&jobQueue))
;
for (i32 i = 0; i < DQN_ARRAY_COUNT(globalDebugCounterMemoize); i++)
DQN_ASSERT(globalDebugCounterMemoize[i]);
DqnWin32_OutputDebugString("\nFinal incremented value: %d\n", globalDebugCounter);
DQN_ASSERT(globalDebugCounter == DQN_ARRAY_COUNT(globalDebugCounterMemoize));
#endif
}
else
{
// TODO(doyle): Semaphore failed.
DqnWin32_DisplayLastError("CreateSemaphore() failed");
}
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Update Loop // Update Loop
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -576,7 +774,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Update State // Update State
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
f64 startFrameTimeInS = DqnTime_NowInS(); f64 startFrameTimeInS = DqnTimer_NowInS();
FILETIME lastWriteTime = Win32GetLastWriteTime(dllPath); FILETIME lastWriteTime = Win32GetLastWriteTime(dllPath);
if (CompareFileTime(&lastWriteTime, &dllCode.lastWriteTime) != 0) if (CompareFileTime(&lastWriteTime, &dllCode.lastWriteTime) != 0)
@ -587,7 +785,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
} }
{ {
platformInput.timeNowInS = DqnTime_NowInS(); platformInput.timeNowInS = DqnTimer_NowInS();
platformInput.deltaForFrame = (f32)frameTimeInS; platformInput.deltaForFrame = (f32)frameTimeInS;
Win32ProcessMessages(mainWindow, &platformInput); Win32ProcessMessages(mainWindow, &platformInput);
@ -599,8 +797,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
if (dllCode.DTR_Update) if (dllCode.DTR_Update)
{ {
dllCode.DTR_Update(&platformBuffer, &platformInput, dllCode.DTR_Update(&platformBuffer, &platformInput, &globalPlatformMemory);
&globalPlatformMemory);
} }
} }
@ -626,7 +823,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
// Frame Limiting // Frame Limiting
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
{ {
f64 workTimeInS = DqnTime_NowInS() - startFrameTimeInS; f64 workTimeInS = DqnTimer_NowInS() - startFrameTimeInS;
if (workTimeInS < targetSecondsPerFrame) if (workTimeInS < targetSecondsPerFrame)
{ {
DWORD remainingTimeInMs = DWORD remainingTimeInMs =
@ -635,7 +832,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
} }
} }
frameTimeInS = DqnTime_NowInS() - startFrameTimeInS; frameTimeInS = DqnTimer_NowInS() - startFrameTimeInS;
f32 msPerFrame = 1000.0f * (f32)frameTimeInS; f32 msPerFrame = 1000.0f * (f32)frameTimeInS;
f32 framesPerSecond = 1.0f / (f32)frameTimeInS; f32 framesPerSecond = 1.0f / (f32)frameTimeInS;

View File

@ -16,6 +16,11 @@ if %errorlevel%==0 (
ctags -R ctags -R
) )
where /q gtags
if %errorlevel%==0 (
gtags
)
set ProjectName=dtrenderer set ProjectName=dtrenderer
ctime -begin ..\src\%ProjectName%.ctm ctime -begin ..\src\%ProjectName%.ctm
@ -29,7 +34,6 @@ REM EHa- disable exception handling (currently it's on /EHsc since libraries n
REM GR- disable c runtime type information (we don't use) REM GR- disable c runtime type information (we don't use)
REM MD use dynamic runtime library REM MD use dynamic runtime library
REM MT use static runtime library, so build and link it into exe REM MT use static runtime library, so build and link it into exe
REM Od disables optimisations
REM Oi enable intrinsics optimisation, let us use CPU intrinsics if there is one REM Oi enable intrinsics optimisation, let us use CPU intrinsics if there is one
REM instead of generating a call to external library (i.e. CRT). REM instead of generating a call to external library (i.e. CRT).
REM Zi enables debug data, Z7 combines the debug files into one. REM Zi enables debug data, Z7 combines the debug files into one.
@ -39,28 +43,47 @@ REM wd4100 unused argument parameters
REM wd4201 nonstandard extension used: nameless struct/union REM wd4201 nonstandard extension used: nameless struct/union
REM wd4189 local variable is initialised but not referenced REM wd4189 local variable is initialised but not referenced
REM wd4505 unreferenced local function not used will be removed REM wd4505 unreferenced local function not used will be removed
set CompileFlags=-EHsc -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -O2 -FAsc /I..\src\external\ set CompileFlags=-EHsc -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -FAsc /I..\src\external\
set DLLFlags=/Fm%ProjectName% /Fo%ProjectName% /Fa%ProjectName% /Fe%ProjectName% set DLLFlags=/Fm%ProjectName% /Fo%ProjectName% /Fa%ProjectName% /Fe%ProjectName%
set Win32Flags=/FmWin32DTRenderer /FeWin32DTRenderer set Win32Flags=/FmWin32DTRenderer /FeWin32DTRenderer
REM Link libraries
set LinkLibraries=user32.lib kernel32.lib gdi32.lib
REM incremental:no, turn incremental builds off
REM opt:ref, try to remove functions from libs that are not referenced at all
set LinkFlags=-incremental:no -opt:ref -subsystem:WINDOWS -machine:x64 -nologo
set DebugMode=1
if %DebugMode%==1 goto :DebugFlags
goto :ReleaseFlags
:DebugFlags
REM Od disables optimisations
REM RTC1 runtime error checks, only possible with optimisations disabled
set CompileFlags=%CompileFlags% -Od -RTC1
goto compile
:ReleaseFlags
REM opt:icf, COMDAT folding for debugging release build
REM DEBUG:[FULL|NONE] enforce debugging for release build
set CompileFlags=%CompileFlags% -O2
set LinkFlags=%LinkFlags%
REM ////////////////////////////////////////////////////////////////////////////
REM Compile
REM ////////////////////////////////////////////////////////////////////////////
:compile
REM Clean time necessary for hours <10, which produces H:MM:SS.SS where the REM Clean time necessary for hours <10, which produces H:MM:SS.SS where the
REM first character of time is an empty space. CleanTime will pad a 0 if REM first character of time is an empty space. CleanTime will pad a 0 if
REM necessary. REM necessary.
set CleanTime=%time: =0% set CleanTime=%time: =0%
set TimeStamp=%date:~10,4%%date:~7,2%%date:~4,2%_%CleanTime:~0,2%%CleanTime:~3,2%%CleanTime:~6,2% set TimeStamp=%date:~10,4%%date:~7,2%%date:~4,2%_%CleanTime:~0,2%%CleanTime:~3,2%%CleanTime:~6,2%
REM Link libraries
set LinkLibraries=user32.lib kernel32.lib gdi32.lib
REM incremental:no, turn incremental builds off
REM opt:ref, try to remove functions from libs that are not referenced at all
set LinkFlags=-incremental:no -opt:ref -subsystem:WINDOWS -machine:x64 -nologo
REM ////////////////////////////////////////////////////////////////////////////
REM Compile
REM ////////////////////////////////////////////////////////////////////////////
del *.pdb >NUL 2>NUL del *.pdb >NUL 2>NUL
cl %CompileFlags% %Win32Flags% ..\src\Win32DTRenderer.cpp /link %LinkLibraries% %LinkFlags% cl %CompileFlags% %Win32Flags% ..\src\Win32DTRenderer.cpp /link %LinkLibraries% %LinkFlags%
REM cl /P ..\src\Win32DTRenderer.cpp
REM cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link ..\src\external\easy\easy_profiler.lib /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags% REM cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link ..\src\external\easy\easy_profiler.lib /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags%
cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags% cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags%

3212
src/dqn.h

File diff suppressed because it is too large Load Diff