Compare commits

..

1 Commits

Author SHA1 Message Date
371ece0ce3 Add naiive SSAA for primitive triangles only 2017-06-14 12:22:14 +10:00
11 changed files with 1560 additions and 3163 deletions

View File

@ -11,7 +11,7 @@
PlatformFlags globalDTRPlatformFlags; PlatformFlags globalDTRPlatformFlags;
// #include <algorithm> // #include <algorithm>
void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input, void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const input,
PlatformMemory *const memory) PlatformMemory *const memory)
{ {
#if 1 #if 1
@ -835,11 +835,11 @@ void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input,
#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(renderContext, state->font, DTRRender_Text(renderBuffer, 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(renderContext, p - radius, p + radius, pColor); DTRRender_Rectangle(renderBuffer, p - radius, p + radius, pColor);
} }
DqnV2 halfRadius = radius * 0.5f; DqnV2 halfRadius = radius * 0.5f;
@ -851,10 +851,10 @@ void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input,
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(renderContext, state->font, DTRRender_Text(renderBuffer, 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(renderContext, p - radius, p + radius, pColor); DTRRender_Rectangle(renderBuffer, p - radius, p + radius, pColor);
if (i + 1 <= skyPIndex && i > 0) if (i + 1 <= skyPIndex && i > 0)
{ {
@ -863,7 +863,7 @@ void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input,
DqnV2 pMid = p + halfRadius; DqnV2 pMid = p + halfRadius;
DqnV2 prevPMid = prevP + halfRadius; DqnV2 prevPMid = prevP + halfRadius;
DTRRender_Line(renderContext, DqnV2i_V2(prevPMid), DqnV2i_V2(pMid), DTRRender_Line(renderBuffer, DqnV2i_V2(prevPMid), DqnV2i_V2(pMid),
DqnV4_4f(255, 0, 0, 255)); DqnV4_4f(255, 0, 0, 255));
} }
} }
@ -895,23 +895,18 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
state = (DTRState *)memory->context; state = (DTRState *)memory->context;
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Init // Init Memory Stacks
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
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
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
DTRAsset_InitGlobalState(); DTRAsset_InitGlobalState();
const f32 FONT_SIZE = 14;
DTRAsset_LoadFontToBitmap(input->api, &memory->mainStack, tempStack, &state->font, DTRAsset_LoadFontToBitmap(input->api, &memory->mainStack, tempStack, &state->font,
"Roboto-bold.ttf", DqnV2i_2i(256, 256), DqnV2i_2i(' ', '~'), 12); "Roboto-bold.ttf", DqnV2i_2i(256, 256), DqnV2i_2i(' ', '~'), FONT_SIZE);
DTRAsset_LoadBitmap(input->api, assetStack, DTRAsset_LoadBitmap(input->api, assetStack,
tempStack, &state->bitmap, "tree00.bmp"); tempStack, &state->bitmap, "tree00.bmp");
@ -935,23 +930,17 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
if (DTR_DEBUG) if (DTR_DEBUG)
{ {
DTRDebug_TestMeshFaceAndVertexParser(&state->mesh); DTRDebug_TestMeshFaceAndVertexParser(&state->mesh);
bool regionValid;
auto memRegion = DqnMemStackTempRegionGuard(&memory->tempStack, &regionValid); DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->tempStack);
if (regionValid)
{
DTRBitmap test = {}; DTRBitmap test = {};
DTRAsset_LoadBitmap(input->api, assetStack, &memory->tempStack, &test, DTRAsset_LoadBitmap(input->api, assetStack, &memory->tempStack, &test, "byte_read_check.bmp");
"byte_read_check.bmp"); DqnMemStack_EndTempRegion(tmp);
} }
} }
} DqnTempMemStack tempStackMemRegion = DqnMemStack_BeginTempRegion(&memory->tempStack);
{
bool regionValid;
auto tempMemRegion = DqnMemStackTempRegionGuard(&memory->tempStack, &regionValid);
if (regionValid)
{
size_t debugSize = DQN_MEGABYTE(1); size_t debugSize = DQN_MEGABYTE(1);
u8 *debugMemory = (u8 *)DqnMemStack_Push(&memory->tempStack, debugSize); u8 *debugMemory = (u8 *)DqnMemStack_Push(&memory->tempStack, debugSize);
DqnMemStack_InitWithFixedMem(&globalDebug.memStack, debugMemory, debugSize); DqnMemStack_InitWithFixedMem(&globalDebug.memStack, debugMemory, debugSize);
@ -962,31 +951,16 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
renderBuffer.height = platformRenderBuffer->height; renderBuffer.height = platformRenderBuffer->height;
renderBuffer.bytesPerPixel = platformRenderBuffer->bytesPerPixel; renderBuffer.bytesPerPixel = platformRenderBuffer->bytesPerPixel;
renderBuffer.memory = (u8 *)platformRenderBuffer->memory; renderBuffer.memory = (u8 *)platformRenderBuffer->memory;
renderBuffer.renderLock = state->renderLock;
u32 zBufferSize = platformRenderBuffer->width * platformRenderBuffer->height; u32 zBufferSize = platformRenderBuffer->width * platformRenderBuffer->height;
renderBuffer.zBuffer = (f32 *)DqnMemStack_Push( renderBuffer.zBuffer = (f32 *)DqnMemStack_Push(&memory->tempStack,
&memory->tempStack, zBufferSize * sizeof(*renderBuffer.zBuffer)); zBufferSize * sizeof(*renderBuffer.zBuffer));
renderBuffer.pixelLockTable = (bool *)DqnMemStack_Push( for (u32 i = 0; i < zBufferSize; i++) renderBuffer.zBuffer[i] = DQN_F32_MIN;
&memory->tempStack, zBufferSize * sizeof(*renderBuffer.pixelLockTable));
for (u32 i = 0; i < zBufferSize; i++)
{
renderBuffer.zBuffer[i] = DQN_F32_MIN;
renderBuffer.pixelLockTable[i] = false;
}
DTRRenderContext renderContext = {};
renderContext.multithread = true;
renderContext.renderBuffer = &renderBuffer;
renderContext.tempStack = &memory->tempStack;
renderContext.api = &input->api;
renderContext.jobQueue = input->jobQueue;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Update and Render // Update and Render
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
DTRRender_Clear(renderContext, DqnV3_3f(0.5f, 0.0f, 1.0f)); DTRRender_Clear(&renderBuffer, DqnV3_3f(0.0f, 0.0f, 0.0f));
#if 1 #if 1
DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1); DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1);
@ -1007,25 +981,27 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
DqnV3 t4[3] = {DqnV3_3i(100, 150, 0), DqnV3_3i(200, 150, 0), DqnV3_3i(200, 250, 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)}; DqnV3 t5[3] = {DqnV3_3i(300, 150, 0), DqnV3_3i(201, 150, 0), DqnV3_3i(200, 250, 0)};
DTRRenderTransform rotatingXform = DTRRender_DefaultTriangleTransform(); if (1)
rotatingXform.rotation = rotation;
if (0)
{ {
DTRDebug_BeginCycleCount(
"DTR_Update_RenderPrimitiveTriangles", DTRRenderTransform rotatingXform = DTRRender_DefaultTriangleTransform();
rotatingXform.rotation = rotation * 0.25f;
DTRDebug_BeginCycleCount("DTR_Update_RenderPrimitiveTriangles",
DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles); DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles);
DTRRender_Triangle(renderContext, t0[0], t0[1], t0[2], colorRed); DTRRenderTransform scaleXform = DTRRender_DefaultTriangleTransform();
DTRRender_Triangle(renderContext, t1[0], t1[1], t1[2], colorRed); scaleXform.scale = DqnV3_1f(5);
DTRRender_Triangle(renderContext, t3[0], t3[1], t3[2], colorRed, rotatingXform); DTRRender_Triangle(&renderBuffer, t0[0], t0[1], t0[2], colorRed);
DTRRender_Triangle(renderContext, t2[0], t2[1], t2[2], colorRed); DTRRender_Triangle(&renderBuffer, t1[0], t1[1], t1[2], colorRed);
DTRRender_Triangle(renderContext, t4[0], t4[1], t4[2], colorRed); DTRRender_Triangle(&renderBuffer, t3[0], t3[1], t3[2], colorRed, rotatingXform);
DTRRender_Triangle(renderContext, t5[0], t5[1], t5[2], colorRed); DTRRender_Triangle(&renderBuffer, t2[0], t2[1], t2[2], colorRed);
DTRRender_Triangle(&renderBuffer, t4[0], t4[1], t4[2], colorRed);
DTRRender_Triangle(&renderBuffer, t5[0], t5[1], t5[2], colorRed);
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles); DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles);
} }
if (1) if (0)
{ {
LOCAL_PERSIST bool runTinyRendererOnce = false; LOCAL_PERSIST bool runTinyRendererOnce = false;
if (1 && runTinyRendererOnce) if (1 && runTinyRendererOnce)
@ -1034,8 +1010,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
runTinyRendererOnce = false; runTinyRendererOnce = false;
} }
DTRDebug_BeginCycleCount("DTR_Update_RenderModel", DTRDebug_BeginCycleCount("DTR_Update_RenderModel", DTRDebugCycleCount_DTR_Update_RenderModel);
DTRDebugCycleCount_DTR_Update_RenderModel);
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Draw Loaded Model // Draw Loaded Model
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -1045,7 +1020,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
DqnV3 modelP = DqnV3_3f(0, 0, 0); DqnV3 modelP = DqnV3_3f(0, 0, 0);
LOCAL_PERSIST f32 modelRotation = 0; LOCAL_PERSIST f32 modelRotation = 0;
modelRotation += (input->deltaForFrame * 20.0f); modelRotation += (input->deltaForFrame * 80.0f);
DqnV3 axis = DqnV3_3f(0, 1, 0); DqnV3 axis = DqnV3_3f(0, 1, 0);
DTRRenderTransform transform = DTRRender_DefaultTransform(); DTRRenderTransform transform = DTRRender_DefaultTransform();
@ -1058,8 +1033,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
lighting.vector = LIGHT; lighting.vector = LIGHT;
lighting.color = DqnV4_4f(1, 1, 1, 1); lighting.color = DqnV4_4f(1, 1, 1, 1);
DTRRender_Mesh(renderContext, input->jobQueue, mesh, lighting, modelP, DTRRender_Mesh(&renderBuffer, mesh, lighting, modelP, transform);
transform);
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderModel); DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderModel);
} }
} }
@ -1070,7 +1044,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
DTRRenderTransform transform = DTRRender_DefaultTransform(); DTRRenderTransform transform = DTRRender_DefaultTransform();
transform.rotation = rotation + 45; transform.rotation = rotation + 45;
DTRRender_Rectangle(renderContext, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f), DTRRender_Rectangle(&renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f),
DqnV4_4f(0, 1.0f, 1.0f, 1.0f), transform); DqnV4_4f(0, 1.0f, 1.0f, 1.0f), transform);
} }
@ -1084,35 +1058,20 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
bitmapP.x += 2.0f * sinf((f32)input->timeNowInS * 0.5f); bitmapP.x += 2.0f * sinf((f32)input->timeNowInS * 0.5f);
f32 cAngle = (f32)input->timeNowInS; f32 cAngle = (f32)input->timeNowInS;
DqnV4 color = DqnV4 color = DqnV4_4f(0.5f + 0.5f * sinf(cAngle), 0.5f + 0.5f * sinf(2.9f * cAngle),
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); 0.5f + 0.5f * cosf(10.0f * cAngle), 1.0f);
DTRRender_Bitmap(renderContext, &state->bitmap, bitmapP, transform, color); DTRRender_Bitmap(&renderBuffer, &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, renderContext, input, memory); DTRDebug_Update(state, &renderBuffer, input, memory);
} DqnMemStack_EndTempRegion(tempStackMemRegion);
while (input->api.QueueTryExecuteNextJob(input->jobQueue) ||
!input->api.QueueAllJobsComplete(input->jobQueue))
;
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// End Update // End Update
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
if (DTR_DEBUG)
{
DQN_ASSERT(input->api.QueueAllJobsComplete(input->jobQueue));
for (i32 i = 0; i < DQN_ARRAY_COUNT(memory->stacks); i++) for (i32 i = 0; i < DQN_ARRAY_COUNT(memory->stacks); i++)
{ DQN_ASSERT(memory->stacks[i].tempStackCount == 0);
if (&memory->stacks[i] == &memory->tempStack) continue;
DQN_ASSERT(memory->stacks[i].tempRegionCount == 0);
}
DqnMemStack_ClearCurrBlock(&memory->tempStack, true);
}
} }

View File

@ -13,8 +13,6 @@ 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,26 +196,16 @@ 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
WavefModel dummy_ = {}; bool result = false;
WavefModel *obj = &dummy_; DqnTempMemStack tmpAssetRegion = DqnMemStack_BeginTempRegion(memStack);
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,
@ -240,6 +230,9 @@ 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;
@ -593,7 +586,7 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac
DQN_ASSERT(DQN_INVALID_CODE_PATH); DQN_ASSERT(DQN_INVALID_CODE_PATH);
} }
DqnMemStackTempRegion_End(tmpAssetRegion); DqnMemStack_EndTempRegion(tmpAssetRegion);
if (modelBlock) if (modelBlock)
{ {
result = true; result = true;
@ -606,7 +599,7 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac
cleanup: cleanup:
api.FileClose(&file); api.FileClose(&file);
if(!result) DqnMemStackTempRegion_End(tmpAssetRegion); if(!result) DqnMemStack_EndTempRegion(tmpAssetRegion);
return result; return result;
} }
@ -630,22 +623,14 @@ 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
stbtt_fontinfo fontInfo = {};
stbtt_pack_context fontPackContext = {};
bool result = false; bool result = false;
bool regionValid; DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tmpMemStack);
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); u8 *rawBytes = (u8 *)DqnMemStack_Push(tmpMemStack, file.size);
size_t bytesRead = api.FileRead(&file, rawBytes, file.size); size_t bytesRead = api.FileRead(&file, rawBytes, file.size);
stbtt_fontinfo fontInfo = {};
stbtt_pack_context fontPackContext = {};
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);
@ -707,6 +692,7 @@ 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;
@ -767,7 +753,7 @@ 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;
DqnMemStackTempRegionGuard tmpMemRegion = tempStack->TempRegionGuard(); DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack);
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);
@ -844,6 +830,7 @@ 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,10 +77,8 @@ void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *cons
} }
} }
bool regionValid; DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack);
auto memRegion = DqnMemStackTempRegionGuard(tempStack, &regionValid);
if (regionValid)
{
size_t bufSize = DQN_MEGABYTE(16); size_t bufSize = DQN_MEGABYTE(16);
char *bufString = (char *)DqnMemStack_Push(tempStack, bufSize); char *bufString = (char *)DqnMemStack_Push(tempStack, bufSize);
char *bufPtr = bufString; char *bufPtr = bufString;
@ -102,7 +100,8 @@ void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *cons
size_t writeSize = (size_t)bufPtr - (size_t)bufString; size_t writeSize = (size_t)bufPtr - (size_t)bufString;
size_t bytesWritten = api->FileWrite(&file, (u8 *)bufString, writeSize); size_t bytesWritten = api->FileWrite(&file, (u8 *)bufString, writeSize);
api->FileClose(&file); api->FileClose(&file);
}
DqnMemStack_EndTempRegion(tmpMemRegion);
} }
} }
@ -119,7 +118,7 @@ void DTRDebug_PushText(const char *const formatStr, ...)
if (DTR_DEBUG) if (DTR_DEBUG)
{ {
DTRDebug *const debug = &globalDebug; DTRDebug *const debug = &globalDebug;
if (!debug->renderContext->renderBuffer) return; if (!debug->renderBuffer) return;
char str[1024] = {}; char str[1024] = {};
@ -131,7 +130,7 @@ void DTRDebug_PushText(const char *const formatStr, ...)
} }
va_end(argList); va_end(argList);
DTRRender_Text(*debug->renderContext, *debug->font, debug->displayP, str, DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str,
debug->displayColor); debug->displayColor);
debug->displayP.y += globalDebug.displayYOffset; debug->displayP.y += globalDebug.displayYOffset;
} }
@ -200,25 +199,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.renderContext, *globalDebug.font, DTRRender_Text(globalDebug.renderBuffer, *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,
DTRRenderContext renderContext, DTRRenderBuffer *const renderBuffer,
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->renderContext = &renderContext; debug->renderBuffer = renderBuffer;
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, 0.85f);
if (debug->font->bitmap && debug->renderContext) if (debug->font->bitmap && debug->renderBuffer)
{ {
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);
@ -271,7 +270,7 @@ void DTRDebug_Update(DTRState *const state,
// End Debug Update // End Debug Update
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
debug->displayP = debug->displayP =
DqnV2_2i(0, debug->renderContext->renderBuffer->height + globalDebug.displayYOffset); DqnV2_2i(0, debug->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

@ -89,7 +89,7 @@ typedef struct DTRDebugCycles
typedef struct DTRDebug typedef struct DTRDebug
{ {
struct DTRFont *font; struct DTRFont *font;
struct DTRRenderContext *renderContext; struct DTRRenderBuffer *renderBuffer;
struct PlatformInput *input; struct PlatformInput *input;
DqnMemStack memStack; DqnMemStack memStack;

View File

@ -4,11 +4,6 @@
#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),
@ -29,47 +24,11 @@ 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;
@ -77,23 +36,8 @@ typedef struct PlatformAPI
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,
@ -154,7 +98,6 @@ typedef struct PlatformInput
PlatformAPI api; PlatformAPI api;
PlatformMouse mouse; PlatformMouse mouse;
PlatformJobQueue *jobQueue;
union { union {
KeyState key[key_count]; KeyState key[key_count];
struct struct
@ -188,9 +131,6 @@ typedef struct PlatformInput
}; };
} PlatformInput; } PlatformInput;
////////////////////////////////////////////////////////////////////////////////
// Platform Memory
////////////////////////////////////////////////////////////////////////////////
typedef struct PlatformMemory typedef struct PlatformMemory
{ {
union { union {
@ -206,9 +146,6 @@ 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,10 +121,9 @@ 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(DTRRenderContext context, const i32 x, const i32 y, FILE_SCOPE inline void SetPixel(DTRRenderBuffer *const renderBuffer, 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;
@ -190,18 +189,15 @@ FILE_SCOPE inline void SetPixel(DTRRenderContext context, const i32 x, const i32
DTRDebug_CounterIncrement(DTRDebugCounter_SetPixels); DTRDebug_CounterIncrement(DTRDebugCounter_SetPixels);
} }
void DTRRender_Text(DTRRenderContext context, void DTRRender_Text(DTRRenderBuffer *const renderBuffer,
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);
@ -266,7 +262,7 @@ void DTRRender_Text(DTRRenderContext context,
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(context, actualX, actualY, resultColor, ColorSpace_Linear); SetPixel(renderBuffer, actualX, actualY, resultColor, ColorSpace_Linear);
} }
} }
} }
@ -291,10 +287,9 @@ FILE_SCOPE void TransformPoints(const DqnV2 origin, DqnV2 *const pList,
} }
} }
void DTRRender_Line(DTRRenderContext context, DqnV2i a, void DTRRender_Line(DTRRenderBuffer *const renderBuffer, 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();
@ -344,7 +339,7 @@ void DTRRender_Line(DTRRenderContext context, 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(context, *plotX, *plotY, color, ColorSpace_Linear); SetPixel(renderBuffer, *plotX, *plotY, color, ColorSpace_Linear);
distAccumulator += distFromPixelOrigin; distAccumulator += distFromPixelOrigin;
if (distAccumulator > run) if (distAccumulator > run)
@ -412,13 +407,10 @@ FILE_SCOPE DqnRect GetBoundingBox(const DqnV2 *const pList, const i32 numP)
return result; return result;
} }
void DTRRender_Rectangle(DTRRenderContext context, DqnV2 min, DqnV2 max, void DTRRender_Rectangle(DTRRenderBuffer *const renderBuffer, 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
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -469,7 +461,7 @@ void DTRRender_Rectangle(DTRRenderContext context, DqnV2 min, DqnV2 max,
} }
} }
if (pIsInside) SetPixel(context, bufferX, bufferY, color, ColorSpace_Linear); if (pIsInside) SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear);
} }
} }
} }
@ -481,7 +473,7 @@ void DTRRender_Rectangle(DTRRenderContext context, DqnV2 min, DqnV2 max,
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(context, bufferX, bufferY, color, ColorSpace_Linear); SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear);
} }
} }
} }
@ -493,20 +485,20 @@ void DTRRender_Rectangle(DTRRenderContext context, DqnV2 min, DqnV2 max,
{ {
// Draw Bounding box // Draw Bounding box
{ {
DTRRender_Line(context, DqnV2i_2f(min.x, min.y), DqnV2i_2f(min.x, max.y), color); DTRRender_Line(renderBuffer, DqnV2i_2f(min.x, min.y), DqnV2i_2f(min.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(min.x, max.y), DqnV2i_2f(max.x, max.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, max.y), DqnV2i_2f(max.x, min.y), color);
DTRRender_Line(context, DqnV2i_2f(max.x, min.y), DqnV2i_2f(min.x, min.y), color); DTRRender_Line(renderBuffer, 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(context, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green); DTRRender_Line(renderBuffer, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green);
DTRRender_Line(context, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green); DTRRender_Line(renderBuffer, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green);
DTRRender_Line(context, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), green); DTRRender_Line(renderBuffer, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), green);
DTRRender_Line(context, DqnV2i_V2(pList[3]), DqnV2i_V2(pList[0]), green); DTRRender_Line(renderBuffer, DqnV2i_V2(pList[3]), DqnV2i_V2(pList[0]), green);
} }
} }
@ -617,12 +609,10 @@ 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(DTRRenderContext context, const i32 x, const i32 y, FILE_SCOPE inline void SIMDSetPixel(DTRRenderBuffer *const renderBuffer, 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;
@ -630,20 +620,20 @@ FILE_SCOPE inline void SIMDSetPixel(DTRRenderContext context, const i32 x, const
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 = bool needGammaFix = (alpha > 0.0f || alpha < (1.0f + COLOR_EPSILON)) && (colorSpace == ColorSpace_SRGB);
(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, (f32)((srcPixel >> 0) & 0xFF), __m128 src = _mm_set_ps(0,
(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);
@ -668,6 +658,8 @@ FILE_SCOPE inline void SIMDSetPixel(DTRRenderContext context, const i32 x, const
(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
@ -716,7 +708,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(DTRRenderContext context, const DqnV2 *const pList, FILE_SCOPE void DebugRenderMarkers(DTRRenderBuffer *const renderBuffer, 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)
{ {
@ -733,10 +725,10 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const
{ {
DqnRect bounds = GetBoundingBox(pList, pListSize); DqnRect bounds = GetBoundingBox(pList, pListSize);
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.min.y), DqnV2i_2f(bounds.min.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.min.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.max.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.max.y), DqnV2i_2f(bounds.max.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); DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.max.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.min.y), red);
} }
// Draw Coordinate Basis // Draw Coordinate Basis
@ -751,9 +743,9 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const
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(context, DqnV2i_V2(origin), DTRRender_Line(renderBuffer, DqnV2i_V2(origin),
DqnV2i_V2(origin) + DqnV2i_V2(xAxis * axisLen), coordSysColor); DqnV2i_V2(origin) + DqnV2i_V2(xAxis * axisLen), coordSysColor);
DTRRender_Line(context, DqnV2i_V2(origin), DTRRender_Line(renderBuffer, DqnV2i_V2(origin),
DqnV2i_V2(origin) + DqnV2i_V2(yAxis * axisLen), coordSysColor); DqnV2i_V2(origin) + DqnV2i_V2(yAxis * axisLen), coordSysColor);
} }
} }
@ -765,40 +757,11 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const
for (i32 i = 0; i < pListSize; i++) for (i32 i = 0; i < pListSize; i++)
{ {
DqnV2 p = pList[i]; DqnV2 p = pList[i];
DTRRender_Rectangle(context, p - DqnV2_1f(5), p + DqnV2_1f(5), colorList[i]); DTRRender_Rectangle(renderBuffer, 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 \
{ \ { \
@ -817,19 +780,21 @@ FILE_SCOPE inline void SetCurrZDepth(DTRRenderContext context, i32 posX, i32 pos
DTRDebug_EndCycleCount(DTRDebugCycleCount_SIMD##type); \ DTRDebug_EndCycleCount(DTRDebugCycleCount_SIMD##type); \
} while (0) } while (0)
FILE_SCOPE void FILE_SCOPE void SIMDRasteriseTrianglePixel(DTRRenderBuffer *const renderBuffer,
SIMDRasteriseTrianglePixel(DTRRenderContext context, const DTRBitmap *const texture, const i32 posX, const DTRBitmap *const texture, const i32 posX,
const i32 posY, const i32 maxX, const DqnV2 uv1, const DqnV2 uv2SubUv1, const i32 posY, const i32 maxX, const DqnV2 uv1,
const DqnV2 uv3SubUv1, const __m128 simdColor, const __m128 triangleZ, const DqnV2 uv2SubUv1, const DqnV2 uv3SubUv1,
const __m128 signedArea, const __m128 invSignedAreaParallelogram_4x, const __m128 simdColor, const __m128 triangleZ,
const f32 preserveAlpha, const bool ignoreLight, const __m128 p1Light, const __m128 signedArea,
const __m128 p2Light, const __m128 p3Light) const __m128 invSignedAreaParallelogram_4x)
{ {
DTRRenderBuffer *const renderBuffer = context.renderBuffer;
const __m128 ZERO_4X = _mm_set_ps1(0.0f); const __m128 ZERO_4X = _mm_set_ps1(0.0f);
const u32 IS_GREATER_MASK = 0xF; const u32 IS_GREATER_MASK = 0xF;
const u32 zBufferPitch = renderBuffer->width; 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
{ {
__m128 isGreater = _mm_cmpge_ps(signedArea, ZERO_4X); __m128 isGreater = _mm_cmpge_ps(signedArea, ZERO_4X);
@ -838,51 +803,32 @@ SIMDRasteriseTrianglePixel(DTRRenderContext context, const DTRBitmap *const text
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 barycentric = _mm_mul_ps(signedArea, invSignedAreaParallelogram_4x);
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric); __m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
f32 pixelZDepth = ((f32 *)&barycentricZ)[0] + ((f32 *)&barycentricZ)[1] +
((f32 *)&barycentricZ)[2];
i32 zBufferIndex = posX + (posY * zBufferPitch); i32 zBufferIndex = posX + (posY * zBufferPitch);
if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex]) f32 pixelZValue =
((f32 *)&barycentricZ)[0] + ((f32 *)&barycentricZ)[1] + ((f32 *)&barycentricZ)[2];
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
if (pixelZValue > currZValue)
{ {
renderBuffer->zBuffer[zBufferIndex] = pixelZDepth; renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
__m128 finalColor = simdColor; __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) if (texture)
{ {
__m128 texSampledColor = SIMDSampleTextureForTriangle( __m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1,
texture, uv1, uv2SubUv1, uv3SubUv1, barycentric); uv3SubUv1, barycentric);
finalColor = _mm_mul_ps(texSampledColor, finalColor); finalColor = _mm_mul_ps(texSampledColor, simdColor);
}
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(DTRRenderContext context, const DqnV3 p1, const DqnV3 p2, FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, 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,
@ -894,8 +840,6 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
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
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -920,16 +864,16 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Setup SIMD data // Setup SIMD data
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
const u32 NUM_X_PIXELS_TO_SIMD = 1; const u32 NUM_X_PIXELS_TO_SIMD = 2;
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 = _mm_set_ps1(0); __m128 signedAreaPixel1;
// __m128 signedAreaPixel2 = _mm_set_ps1(0); __m128 signedAreaPixel2;
__m128 signedAreaPixelDeltaX = _mm_set_ps1(0); __m128 signedAreaPixelDeltaX;
__m128 signedAreaPixelDeltaY = _mm_set_ps1(0); __m128 signedAreaPixelDeltaY;
__m128 invSignedAreaParallelogram_4x = _mm_set_ps1(0); __m128 invSignedAreaParallelogram_4x;
__m128 triangleZ = _mm_set_ps(0, p3.z, p2.z, p1.z); __m128 triangleZ = _mm_set_ps(0, p3.z, p2.z, p1.z);
{ {
@ -962,7 +906,7 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
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
{ {
@ -978,9 +922,13 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
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
@ -989,10 +937,11 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
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;
@ -1007,26 +956,15 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
__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);
f32 pixelZDepth = ((f32 *)&barycentricZ)[0] + i32 zBufferIndex = posX + (posY * zBufferPitch);
f32 pixelZValue = ((f32 *)&barycentricZ)[0] +
((f32 *)&barycentricZ)[1] + ((f32 *)&barycentricZ)[1] +
((f32 *)&barycentricZ)[2]; ((f32 *)&barycentricZ)[2];
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
i32 zBufferIndex = posX + (posY * zBufferPitch); if (pixelZValue > currZValue)
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]);
@ -1047,28 +985,85 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
if (texture) if (texture)
{ {
__m128 texSampledColor = SIMDSampleTextureForTriangle( __m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
finalColor = _mm_mul_ps(texSampledColor, finalColor); 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);
} }
}
signedAreaPixel1 = _mm_add_ps(signedAreaPixel1, signedAreaPixelDeltaY); // Rasterise buffer(X + 1, Y) pixel
// signedAreaPixel2 = _mm_add_ps(signedAreaPixel2, signedAreaPixelDeltaY); {
__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);
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(DTRRenderContext context, const DqnV3 p1, const DqnV3 p2, FILE_SCOPE void SlowTriangle(DTRRenderBuffer *const renderBuffer, 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,
@ -1076,6 +1071,7 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
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 \
{ \ { \
@ -1095,9 +1091,8 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
} 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);
DTRRenderBuffer *renderBuffer = context.renderBuffer; DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Preamble);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Convert Color // Convert Color
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -1151,39 +1146,75 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
for (i32 bufferX = min.x; bufferX < max.x; bufferX++) for (i32 bufferX = min.x; bufferX < max.x; bufferX++)
{ {
if (signedArea1 >= 0 && signedArea2 >= 0 && signedArea3 >= 0) // TODO(doyle): Use signedArea1/2/3 and subsample increments from the signedAreaDeltas
const u32 NUM_SAMPLES_ALONG_AXIS = 2;
const u32 SAMPLES_PER_PIXEL = DQN_SQUARED(NUM_SAMPLES_ALONG_AXIS);
DQN_ASSERT((NUM_SAMPLES_ALONG_AXIS & 1) == 0);
const f32 SAMPLE_COVERAGE_INCREMENT = 1 / (f32)SAMPLES_PER_PIXEL;
const f32 SAMPLE_XY_INCREMENT = 1 / (f32)NUM_SAMPLES_ALONG_AXIS;
f32 subsampleCoverage = 0;
for (i32 sampleY = 0; sampleY < NUM_SAMPLES_ALONG_AXIS; sampleY++)
{
for (i32 sampleX = 0; sampleX < NUM_SAMPLES_ALONG_AXIS; sampleX++)
{
f32 granularX = sampleX * SAMPLE_XY_INCREMENT;
f32 granularY = sampleY * SAMPLE_XY_INCREMENT;
DqnV2 subsample = DqnV2_2f((f32)bufferX + granularX, (f32)bufferY + granularY);
f32 subsampleSignedArea1 = Triangle2TimesSignedArea(p2.xy, p3.xy, subsample);
f32 subsampleSignedArea2 = Triangle2TimesSignedArea(p3.xy, p1.xy, subsample);
f32 subsampleSignedArea3 = Triangle2TimesSignedArea(p1.xy, p2.xy, subsample);
if (subsampleSignedArea1 >= 0 && subsampleSignedArea2 >= 0 &&
subsampleSignedArea3 >= 0)
{
subsampleCoverage += SAMPLE_COVERAGE_INCREMENT;
}
}
}
DQN_ASSERT(subsampleCoverage >= 0.0f && subsampleCoverage <= 1.0f);
// TODO(doyle): Crashes when using meshes, since we are now sampling
// outside the actual specified mesh, (i.e. pixels just before it
// for SSAA) the barycentric coordinates sample outside the texture.
// Naiive workarounds will cause color artifacts or gaps in rendered
// meshes.
if (subsampleCoverage > 0)
{ {
DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel); DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel);
f32 barycentricA = signedArea1 * invSignedAreaParallelogram;
f32 barycentricB = signedArea2 * invSignedAreaParallelogram; f32 barycentricB = signedArea2 * invSignedAreaParallelogram;
f32 barycentricC = signedArea3 * invSignedAreaParallelogram; f32 barycentricC = signedArea3 * invSignedAreaParallelogram;
i32 zBufferIndex = bufferX + (bufferY * zBufferPitch); i32 zBufferIndex = bufferX + (bufferY * zBufferPitch);
if (context.multithread) f32 pixelZValue = p1.z + (barycentricB * (p2SubP1.z)) + (barycentricC * (p3SubP1.z));
{ f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
bool currLockValue; DQN_ASSERT(zBufferIndex < (renderBuffer->width * renderBuffer->height));
do
{
currLockValue = (bool)context.api->AtomicCompareSwap(
(u32 *)&renderBuffer->pixelLockTable[zBufferIndex], (u32) true,
(u32) false);
} while (currLockValue != false);
}
f32 pixelZDepth = if (pixelZValue >= currZValue)
p1.z + (barycentricB * (p2SubP1.z)) + (barycentricC * (p3SubP1.z));
if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex])
{ {
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
DqnV4 finalColor = color; DqnV4 finalColor = color;
renderBuffer->zBuffer[zBufferIndex] = pixelZDepth; DQN_ASSERT(finalColor.x >= 0);
// NOTE: Multiply everything by the coverage alpha since
// colors need to be premultiplied alpha.
finalColor *= subsampleCoverage;
DQN_ASSERT(finalColor.x >= 0);
if (!ignoreLight) if (!ignoreLight)
{ {
f32 barycentricA = signedArea1 * invSignedAreaParallelogram;
DqnV3 light = (p1Light * barycentricA) + (p2Light * barycentricB) + DqnV3 light = (p1Light * barycentricA) + (p2Light * barycentricB) +
(p3Light * barycentricC); (p3Light * barycentricC);
finalColor.rgb *= light; finalColor.rgb *= light;
DQN_ASSERT(finalColor.x >= 0);
} }
DQN_ASSERT(finalColor.x >= 0);
if (texture) if (texture)
{ {
DqnV2 uv = uv1 + (uv2SubUv1 * barycentricB) + (uv3SubUv1 * barycentricC); DqnV2 uv = uv1 + (uv2SubUv1 * barycentricB) + (uv3SubUv1 * barycentricC);
@ -1214,11 +1245,14 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
color1 *= INV_255; color1 *= INV_255;
color1 = DTRRender_SRGB1ToLinearSpaceV4(color1); color1 = DTRRender_SRGB1ToLinearSpaceV4(color1);
finalColor *= color1; finalColor *= color1;
DQN_ASSERT(finalColor.x >= 0);
} }
SetPixel(context, bufferX, bufferY, finalColor, ColorSpace_Linear); SetPixel(renderBuffer, bufferX, bufferY, finalColor, ColorSpace_Linear);
int breakhere = 5;
} }
renderBuffer->pixelLockTable[zBufferIndex] = false;
DEBUG_SLOW_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel); DEBUG_SLOW_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel);
} }
@ -1262,14 +1296,11 @@ DqnMat4 GLViewport(f32 x, f32 y, f32 width, f32 height)
return result; return result;
} }
FILE_SCOPE void FILE_SCOPE void TexturedTriangleInternal(DTRRenderBuffer *const renderBuffer,
TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting, DqnV3 p1, DqnV3 p2, RenderLightInternal lighting, DqnV3 p1, DqnV3 p2, DqnV3 p3,
DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture,
DqnV4 color, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform())
const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform())
{ {
DTRRenderBuffer *renderBuffer = context.renderBuffer;
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Transform vertexes p1, p2, p3 inplace // Transform vertexes p1, p2, p3 inplace
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -1324,14 +1355,14 @@ TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting,
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// SIMD/Slow Path // SIMD/Slow Path
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
if (globalDTRPlatformFlags.canUseSSE2) if (globalDTRPlatformFlags.canUseSSE2 && 0)
{ {
SIMDTriangle(context, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2, SIMDTriangle(renderBuffer, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2,
lightIntensity3, ignoreLight, texture, color, min, max); lightIntensity3, ignoreLight, texture, color, min, max);
} }
else else
{ {
SlowTriangle(context, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2, SlowTriangle(renderBuffer, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2,
lightIntensity3, ignoreLight, texture, color, min, max); lightIntensity3, ignoreLight, texture, color, min, max);
} }
@ -1344,7 +1375,7 @@ TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting,
bool drawBasis = false; bool drawBasis = false;
bool drawVertexMarkers = false; bool drawVertexMarkers = false;
DebugRenderMarkers(context, pList, DQN_ARRAY_COUNT(pList), transform, drawBoundingBox, DebugRenderMarkers(renderBuffer, pList, DQN_ARRAY_COUNT(pList), transform, drawBoundingBox,
drawBasis, drawVertexMarkers); drawBasis, drawVertexMarkers);
} }
} }
@ -1355,51 +1386,20 @@ FILE_SCOPE RenderLightInternal NullRenderLightInternal()
return result; return result;
} }
void DTRRender_TexturedTriangle(DTRRenderContext context, void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer,
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(context, NullRenderLightInternal(), p1, p2, p3, uv1, uv2, uv3, texture, TexturedTriangleInternal(renderBuffer, NullRenderLightInternal(), p1, p2, p3, uv1, uv2, uv3, texture,
color, transform); color, transform);
} }
typedef struct RenderMeshJob void DTRRender_Mesh(DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh,
DTRRenderLight lighting, const DqnV3 pos,
const DTRRenderTransform transform)
{ {
DTRRenderContext context; if (!mesh) return;
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 = {};
{ {
@ -1502,7 +1502,6 @@ void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue,
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;
@ -1512,92 +1511,43 @@ void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue,
lightingInternal.numNormals = 3; lightingInternal.numNormals = 3;
bool DEBUG_NO_TEX = false; bool DEBUG_NO_TEX = false;
if (context.multithread)
{
RenderMeshJob *jobData = (RenderMeshJob *)DqnMemStack_Push(tempStack, sizeof(*jobData));
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) if (DTR_DEBUG && DEBUG_NO_TEX)
{ {
jobData->tex = NULL; TexturedTriangleInternal(renderBuffer, lightingInternal, v1.xyz, v2.xyz, v3.xyz, uv1,
uv2, uv3, NULL, color);
} }
else else
{ {
jobData->tex = &mesh->tex; TexturedTriangleInternal(renderBuffer, lightingInternal, v1.xyz, v2.xyz, v3.xyz, uv1,
} uv2, uv3, &mesh->tex, color);
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
{
if (DTR_DEBUG && DEBUG_NO_TEX)
{
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(context, DqnV2i_V2(v1.xy), DqnV2i_V2(v2.xy), wireColor); DTRRender_Line(renderBuffer, DqnV2i_V2(v1.xy), DqnV2i_V2(v2.xy),
DTRRender_Line(context, DqnV2i_V2(v2.xy), DqnV2i_V2(v3.xy), wireColor); wireColor);
DTRRender_Line(context, DqnV2i_V2(v3.xy), DqnV2i_V2(v1.xy), wireColor); DTRRender_Line(renderBuffer, DqnV2i_V2(v2.xy), DqnV2i_V2(v3.xy),
wireColor);
DTRRender_Line(renderBuffer, DqnV2i_V2(v3.xy), DqnV2i_V2(v1.xy),
wireColor);
}
} }
} }
if (context.multithread) void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3,
{ DqnV4 color, const DTRRenderTransform transform)
// NOTE(doyle): Complete remaining jobs and wait until all jobs finished
// before leaving function.
while (api->QueueTryExecuteNextJob(jobQueue) || !api->QueueAllJobsComplete(jobQueue))
;
}
}
void DTRRender_Triangle(DTRRenderContext context, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color,
const DTRRenderTransform transform)
{ {
const DqnV2 NO_UV = {}; const DqnV2 NO_UV = {};
DTRBitmap *const NO_TEX = NULL; DTRBitmap *const NO_TEX = NULL;
TexturedTriangleInternal(context, NullRenderLightInternal(), p1, p2, p3, NO_UV, NO_UV, TexturedTriangleInternal(renderBuffer, NullRenderLightInternal(), p1, p2, p3, NO_UV, NO_UV,
NO_UV, NO_TEX, color, transform); NO_UV, NO_TEX, color, transform);
} }
void DTRRender_Bitmap(DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 pos, void DTRRender_Bitmap(DTRRenderBuffer *const renderBuffer, 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();
@ -1771,7 +1721,7 @@ void DTRRender_Bitmap(DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 p
blend.g *= color.g; blend.g *= color.g;
blend.b *= color.b; blend.b *= color.b;
SetPixel(context, bufferX, bufferY, blend, ColorSpace_Linear); SetPixel(renderBuffer, bufferX, bufferY, blend, ColorSpace_Linear);
} }
} }
} }
@ -1785,14 +1735,14 @@ void DTRRender_Bitmap(DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 p
bool drawBasis = true; bool drawBasis = true;
bool drawVertexMarkers = true; bool drawVertexMarkers = true;
DebugRenderMarkers(context, pList, RECT_PLIST_SIZE, transform, drawBoundingBox, DebugRenderMarkers(renderBuffer, pList, RECT_PLIST_SIZE, transform, drawBoundingBox,
drawBasis, drawVertexMarkers); drawBasis, drawVertexMarkers);
} }
} }
void DTRRender_Clear(DTRRenderContext context, DqnV3 color) void DTRRender_Clear(DTRRenderBuffer *const renderBuffer,
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);
@ -1813,4 +1763,3 @@ void DTRRender_Clear(DTRRenderContext context, DqnV3 color)
} }
} }
} }

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,11 +16,9 @@ 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
volatile bool *pixelLockTable; // has (width * height) elements u8 *memory; // Format: XX RR GG BB, and has (width * height * bytesPerPixels) elements
f32 *zBuffer; // zBuffer has (width * height) elements
} DTRRenderBuffer; } DTRRenderBuffer;
@ -76,25 +74,15 @@ 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 (DTRRenderContext context, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1); 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_Line (DTRRenderContext context, DqnV2i a, DqnV2i b, DqnV4 color); void DTRRender_Line (DTRRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color);
void DTRRender_Rectangle (DTRRenderContext context, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform()); void DTRRender_Rectangle (DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform());
void DTRRender_Mesh (DTRRenderContext context, PlatformJobQueue *const jobQueue, DTRMesh *const mesh, DTRRenderLight lighting, const DqnV3 pos, const DTRRenderTransform transform); void DTRRender_Mesh (DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh, DTRRenderLight lighting, const DqnV3 pos, const DTRRenderTransform transform);
void DTRRender_Triangle (DTRRenderContext context, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()); void DTRRender_Triangle (DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, 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_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_Bitmap (DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform = DTRRender_DefaultTransform(), DqnV4 color = DqnV4_4f(1, 1, 1, 1)); 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_Clear (DTRRenderContext context, DqnV3 color); void DTRRender_Clear (DTRRenderBuffer *const renderBuffer, DqnV3 color);
#endif #endif

View File

@ -1,157 +1,18 @@
#define UNICODE
#define _UNICODE
#include "DTRenderer.h" #include "DTRenderer.h"
#include "DTRendererPlatform.h" #include "DTRendererPlatform.h"
#define DQN_WIN32_IMPLEMENTATION
#define DQN_IMPLEMENTATION #define DQN_IMPLEMENTATION
#define DQN_WIN32_IMPLEMENTATION
#include "dqn.h" #include "dqn.h"
#include <Windows.h> #define UNICODE
#include <Windowsx.h> // For GET_X|Y_LPARAM(), mouse input #define _UNICODE
#include <Psapi.h> // For win32 GetProcessMemoryInfo()
FILE_SCOPE PlatformMemory globalPlatformMemory; const char *const DLL_NAME = "dtrenderer.dll";
FILE_SCOPE bool globalRunning; const char *const DLL_TMP_NAME = "dtrenderer_temp.dll";
void Platform_DieGracefully() { globalRunning = false; }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Platform Atomics // Platform API Implementation
////////////////////////////////////////////////////////////////////////////////
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)
{ {
@ -176,7 +37,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;
OutputDebugStringA(string); OutputDebugString(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,
@ -207,7 +68,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;
} }
@ -234,9 +95,9 @@ void Platform_FileClose(PlatformFile *const file)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Win32 Layer // Win32 Layer
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
const char *const DLL_NAME = "dtrenderer.dll"; #include <Windows.h>
const char *const DLL_TMP_NAME = "dtrenderer_temp.dll"; #include <Windowsx.h> // For GET_X|Y_LPARAM(), mouse input
#include <Psapi.h> // For win32 GetProcessMemoryInfo()
typedef struct Win32RenderBitmap typedef struct Win32RenderBitmap
{ {
BITMAPINFO info; BITMAPINFO info;
@ -248,6 +109,8 @@ 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
{ {
@ -287,7 +150,7 @@ FILETIME Win32GetLastWriteTime(const char *const srcName)
{ {
FILETIME lastWriteTime = {}; FILETIME lastWriteTime = {};
WIN32_FILE_ATTRIBUTE_DATA attribData = {}; WIN32_FILE_ATTRIBUTE_DATA attribData = {};
if (GetFileAttributesExA(srcName, GetFileExInfoStandard, &attribData) != 0) if (GetFileAttributesEx(srcName, GetFileExInfoStandard, &attribData) != 0)
{ {
lastWriteTime = attribData.ftLastWriteTime; lastWriteTime = attribData.ftLastWriteTime;
} }
@ -301,7 +164,7 @@ FILE_SCOPE Win32ExternalCode Win32LoadExternalDLL(const char *const srcPath,
{ {
Win32ExternalCode result = {}; Win32ExternalCode result = {};
result.lastWriteTime = lastWriteTime; result.lastWriteTime = lastWriteTime;
CopyFileA(srcPath, tmpPath, false); CopyFile(srcPath, tmpPath, false);
DTR_UpdateFunction *updateFunction = NULL; DTR_UpdateFunction *updateFunction = NULL;
result.dll = LoadLibraryA(tmpPath); result.dll = LoadLibraryA(tmpPath);
@ -332,10 +195,10 @@ FILE_SCOPE void Win32CreateMenu(HWND window)
HMENU menuBar = CreateMenu(); HMENU menuBar = CreateMenu();
{ // File Menu { // File Menu
HMENU menu = CreatePopupMenu(); HMENU menu = CreatePopupMenu();
AppendMenuA(menuBar, MF_STRING | MF_POPUP, (UINT_PTR)menu, "File"); AppendMenu(menuBar, MF_STRING | MF_POPUP, (UINT_PTR)menu, "File");
AppendMenuA(menu, MF_STRING, Win32Menu_FileOpen, "Open"); AppendMenu(menu, MF_STRING, Win32Menu_FileOpen, "Open");
AppendMenuA(menu, MF_STRING, Win32Menu_FileFlushMemory, "Flush Memory"); AppendMenu(menu, MF_STRING, Win32Menu_FileFlushMemory, "Flush Memory");
AppendMenuA(menu, MF_STRING, Win32Menu_FileExit, "Exit"); AppendMenu(menu, MF_STRING, Win32Menu_FileExit, "Exit");
} }
SetMenu(window, menuBar); SetMenu(window, menuBar);
} }
@ -549,13 +412,43 @@ FILE_SCOPE void Win32ProcessMessages(HWND window, PlatformInput *input)
} }
} }
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) // Return the index of the last slash
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,
@ -614,7 +507,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
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;
if (!DQN_ASSERT(globalRenderBitmap.bytesPerPixel >= 1)) return -1; DQN_ASSERT(globalRenderBitmap.bytesPerPixel >= 1);
HDC deviceContext = GetDC(mainWindow); HDC deviceContext = GetDC(mainWindow);
globalRenderBitmap.handle = CreateDIBSection( globalRenderBitmap.handle = CreateDIBSection(
@ -637,130 +530,39 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
char dllTmpPath[MAX_PATH] = {}; char dllTmpPath[MAX_PATH] = {};
{ {
char exeDir[MAX_PATH] = {}; char exeDir[MAX_PATH] = {};
i32 lastSlashIndex = DqnWin32_GetEXEDirectory(exeDir, DQN_ARRAY_COUNT(exeDir)); i32 lastSlashIndex =
if (DQN_ASSERT_MSG(lastSlashIndex != -1, "Not enough space in buffer for exe path")) Win32GetModuleDirectory(exeDir, DQN_ARRAY_COUNT(exeDir));
{ 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);
if (!DQN_ASSERT_MSG((dllNumCopied < DQN_ARRAY_COUNT(dllPath)) && exeDir[lastSlashIndex + 1] = 0;
(dllTmpNumCopied < DQN_ARRAY_COUNT(dllPath)), u32 numCopied = Dqn_sprintf(dllPath, "%s%s", exeDir, DLL_NAME);
"Out of space to form DLL path")) DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllPath));
{
Platform_DieGracefully(); numCopied =
} Dqn_sprintf(dllTmpPath, "%s%s", exeDir, DLL_TMP_NAME);
} DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllTmpPath));
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Platform Data Pre-amble // Platform Data Pre-amble
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
bool memoryInitResult = DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.mainStack, DQN_MEGABYTE(4), true, 4) &&
DqnMemStack_Init(&globalPlatformMemory.mainStack, DQN_MEGABYTE(4), true, 4) | DqnMemStack_Init(&globalPlatformMemory.tempStack, DQN_MEGABYTE(4), true, 4) &&
DqnMemStack_Init(&globalPlatformMemory.tempStack, DQN_MEGABYTE(4), true, 4) | DqnMemStack_Init(&globalPlatformMemory.assetStack, 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.DieGracefully = Platform_DieGracefully;
platformAPI.FileOpen = Platform_FileOpen; platformAPI.FileOpen = Platform_FileOpen;
platformAPI.FileRead = Platform_FileRead; platformAPI.FileRead = Platform_FileRead;
platformAPI.FileWrite = Platform_FileWrite; platformAPI.FileWrite = Platform_FileWrite;
platformAPI.FileClose = Platform_FileClose; platformAPI.FileClose = Platform_FileClose;
platformAPI.Print = Platform_Print; 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
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -774,7 +576,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Update State // Update State
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
f64 startFrameTimeInS = DqnTimer_NowInS(); f64 startFrameTimeInS = DqnTime_NowInS();
FILETIME lastWriteTime = Win32GetLastWriteTime(dllPath); FILETIME lastWriteTime = Win32GetLastWriteTime(dllPath);
if (CompareFileTime(&lastWriteTime, &dllCode.lastWriteTime) != 0) if (CompareFileTime(&lastWriteTime, &dllCode.lastWriteTime) != 0)
@ -785,7 +587,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
} }
{ {
platformInput.timeNowInS = DqnTimer_NowInS(); platformInput.timeNowInS = DqnTime_NowInS();
platformInput.deltaForFrame = (f32)frameTimeInS; platformInput.deltaForFrame = (f32)frameTimeInS;
Win32ProcessMessages(mainWindow, &platformInput); Win32ProcessMessages(mainWindow, &platformInput);
@ -797,7 +599,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
if (dllCode.DTR_Update) if (dllCode.DTR_Update)
{ {
dllCode.DTR_Update(&platformBuffer, &platformInput, &globalPlatformMemory); dllCode.DTR_Update(&platformBuffer, &platformInput,
&globalPlatformMemory);
} }
} }
@ -823,7 +626,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
// Frame Limiting // Frame Limiting
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
{ {
f64 workTimeInS = DqnTimer_NowInS() - startFrameTimeInS; f64 workTimeInS = DqnTime_NowInS() - startFrameTimeInS;
if (workTimeInS < targetSecondsPerFrame) if (workTimeInS < targetSecondsPerFrame)
{ {
DWORD remainingTimeInMs = DWORD remainingTimeInMs =
@ -832,7 +635,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
} }
} }
frameTimeInS = DqnTimer_NowInS() - startFrameTimeInS; frameTimeInS = DqnTime_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,11 +16,6 @@ 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
@ -34,6 +29,7 @@ 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.
@ -43,10 +39,16 @@ 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 -FAsc /I..\src\external\ set CompileFlags=-EHsc -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -Od -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 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 necessary.
set CleanTime=%time: =0%
set TimeStamp=%date:~10,4%%date:~7,2%%date:~4,2%_%CleanTime:~0,2%%CleanTime:~3,2%%CleanTime:~6,2%
REM Link libraries REM Link libraries
set LinkLibraries=user32.lib kernel32.lib gdi32.lib set LinkLibraries=user32.lib kernel32.lib gdi32.lib
@ -54,36 +56,11 @@ REM incremental:no, turn incremental builds off
REM opt:ref, try to remove functions from libs that are not referenced at all 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 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 ////////////////////////////////////////////////////////////////////////////
REM Compile REM Compile
REM //////////////////////////////////////////////////////////////////////////// REM ////////////////////////////////////////////////////////////////////////////
:compile
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 necessary.
set CleanTime=%time: =0%
set TimeStamp=%date:~10,4%%date:~7,2%%date:~4,2%_%CleanTime:~0,2%%CleanTime:~3,2%%CleanTime:~6,2%
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%

3156
src/dqn.h

File diff suppressed because it is too large Load Diff