Compare commits

..

1 Commits

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

View File

@ -13,8 +13,6 @@ typedef struct DTRState
DTRFont font;
DTRBitmap bitmap;
DTRMesh mesh;
struct PlatformLock *renderLock;
} DTRState;
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))
return false; // TODO(doyle): Logging
WavefModel dummy_ = {};
WavefModel *obj = &dummy_;
bool result = false;
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 = {};
memAPI.callback = DumbDynamicArrayMemAPICallback;
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 {
WavefVertexType_Invalid,
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
// memory for locality. Then just throw away the intermediate
// representation.
WavefModel dummy_ = {};
WavefModel *obj = &dummy_;
if (bytesRead != file.size) 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);
}
DqnMemStackTempRegion_End(tmpAssetRegion);
DqnMemStack_EndTempRegion(tmpAssetRegion);
if (modelBlock)
{
result = true;
@ -606,7 +599,7 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac
cleanup:
api.FileClose(&file);
if(!result) DqnMemStackTempRegion_End(tmpAssetRegion);
if(!result) DqnMemStack_EndTempRegion(tmpAssetRegion);
return result;
}
@ -630,22 +623,14 @@ bool DTRAsset_LoadFontToBitmap(const PlatformAPI api, DqnMemStack *const memStac
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
return false; // TODO(doyle): Logging
stbtt_fontinfo fontInfo = {};
stbtt_pack_context fontPackContext = {};
bool result = false;
bool regionValid;
auto tmpMemRegion = DqnMemStackTempRegionGuard(tmpMemStack, &regionValid);
if (!regionValid)
{
// TODO(doyle): Logging
DQN_ASSERT(DQN_INVALID_CODE_PATH);
goto cleanup;
}
bool result = false;
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tmpMemStack);
u8 *rawBytes = (u8 *)DqnMemStack_Push(tmpMemStack, file.size);
size_t bytesRead = api.FileRead(&file, rawBytes, file.size);
stbtt_fontinfo fontInfo = {};
stbtt_pack_context fontPackContext = {};
if (bytesRead != file.size || stbtt_InitFont(&fontInfo, rawBytes, 0) == 0)
{
DQN_ASSERT(DQN_INVALID_CODE_PATH);
@ -707,6 +692,7 @@ bool DTRAsset_LoadFontToBitmap(const PlatformAPI api, DqnMemStack *const memStac
*font = loadedFont;
cleanup:
DqnMemStack_EndTempRegion(tmpMemRegion);
api.FileClose(&file);
return result;
@ -767,9 +753,9 @@ bool DTRAsset_LoadBitmap(const PlatformAPI api, DqnMemStack *const memStack,
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
return result;
DqnMemStackTempRegionGuard tmpMemRegion = tempStack->TempRegionGuard();
u8 *const rawData = (u8 *)DqnMemStack_Push(tempStack, file.size);
size_t bytesRead = api.FileRead(&file, rawData, file.size);
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack);
u8 *const rawData = (u8 *)DqnMemStack_Push (tempStack, file.size);
size_t bytesRead = api.FileRead (&file, rawData, file.size);
if (bytesRead != file.size) goto cleanup;
@ -844,6 +830,7 @@ bool DTRAsset_LoadBitmap(const PlatformAPI api, DqnMemStack *const memStack,
cleanup:
globalSTBImageAllocator = NULL;
DqnMemStack_EndTempRegion(tmpMemRegion);
api.FileClose(&file);
return result;

View File

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

View File

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

View File

@ -4,11 +4,6 @@
#include "dqn.h"
#include <intrin.h>
typedef void PlatformAPI_DieGracefully();
////////////////////////////////////////////////////////////////////////////////
// Platform File I/O
////////////////////////////////////////////////////////////////////////////////
enum PlatformFilePermissionFlag
{
PlatformFilePermissionFlag_Read = (1 << 0),
@ -29,71 +24,20 @@ typedef struct PlatformFile
u32 permissionFlags;
} PlatformFile;
// File I/O API
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 void PlatformAPI_FileClose(PlatformFile *const file);
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
{
PlatformAPI_FileOpen *FileOpen;
PlatformAPI_FileRead *FileRead;
PlatformAPI_FileWrite *FileWrite;
PlatformAPI_FileClose *FileClose;
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_FileOpen *FileOpen;
PlatformAPI_FileRead *FileRead;
PlatformAPI_FileWrite *FileWrite;
PlatformAPI_FileClose *FileClose;
PlatformAPI_Print *Print;
} PlatformAPI;
////////////////////////////////////////////////////////////////////////////////
// Platform Input
////////////////////////////////////////////////////////////////////////////////
enum Key
{
key_up,
@ -152,9 +96,8 @@ typedef struct PlatformInput
f64 timeNowInS;
PlatformFlags flags;
PlatformAPI api;
PlatformMouse mouse;
PlatformJobQueue *jobQueue;
PlatformAPI api;
PlatformMouse mouse;
union {
KeyState key[key_count];
struct
@ -188,9 +131,6 @@ typedef struct PlatformInput
};
} PlatformInput;
////////////////////////////////////////////////////////////////////////////////
// Platform Memory
////////////////////////////////////////////////////////////////////////////////
typedef struct PlatformMemory
{
union {
@ -206,9 +146,6 @@ typedef struct PlatformMemory
void *context;
} PlatformMemory;
////////////////////////////////////////////////////////////////////////////////
// Platform Frame Buffer
////////////////////////////////////////////////////////////////////////////////
typedef struct PlatformRenderBuffer
{
i32 width;

View File

@ -121,10 +121,9 @@ inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color)
}
// 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)
{
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!renderBuffer) return;
if (x < 0 || x > (renderBuffer->width - 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);
}
void DTRRender_Text(DTRRenderContext context,
void DTRRender_Text(DTRRenderBuffer *const renderBuffer,
const DTRFont font, DqnV2 pos, const char *const text,
DqnV4 color, i32 len)
{
if (!text) return;
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!font.bitmap || !font.atlas || !renderBuffer) return;
DTR_DEBUG_EP_TIMED_FUNCTION();
if (len == -1) len = DqnStr_Len(text);
if (len == -1) len = Dqn_strlen(text);
i32 index = 0;
color = DTRRender_SRGB1ToLinearSpaceV4(color);
@ -266,7 +262,7 @@ void DTRRender_Text(DTRRenderContext context,
i32 actualX = (i32)(screenRect.min.x + x);
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)
{
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!renderBuffer) return;
DTR_DEBUG_EP_TIMED_FUNCTION();
@ -344,7 +339,7 @@ void DTRRender_Line(DTRRenderContext context, DqnV2i a,
for (i32 iterateX = 0; iterateX < numIterations; iterateX++)
{
newX = a.x + iterateX;
SetPixel(context, *plotX, *plotY, color, ColorSpace_Linear);
SetPixel(renderBuffer, *plotX, *plotY, color, ColorSpace_Linear);
distAccumulator += distFromPixelOrigin;
if (distAccumulator > run)
@ -412,13 +407,10 @@ FILE_SCOPE DqnRect GetBoundingBox(const DqnV2 *const pList, const i32 numP)
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)
{
DTR_DEBUG_EP_TIMED_FUNCTION();
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!renderBuffer) return;
////////////////////////////////////////////////////////////////////////////
// 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++)
{
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
{
DTRRender_Line(context, 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(context, 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(min.x, min.y), DqnV2i_2f(min.x, max.y), color);
DTRRender_Line(renderBuffer, DqnV2i_2f(min.x, max.y), DqnV2i_2f(max.x, max.y), color);
DTRRender_Line(renderBuffer, DqnV2i_2f(max.x, max.y), DqnV2i_2f(max.x, min.y), color);
DTRRender_Line(renderBuffer, DqnV2i_2f(max.x, min.y), DqnV2i_2f(min.x, min.y), color);
}
// Draw rotating outline
if (transform.rotation > 0)
{
DqnV4 green = DqnV4_4f(0, 1, 0, 1);
DTRRender_Line(context, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green);
DTRRender_Line(context, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green);
DTRRender_Line(context, 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[0]), DqnV2i_V2(pList[1]), green);
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green);
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), 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
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,
const enum ColorSpace colorSpace = ColorSpace_SRGB)
{
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!renderBuffer) return;
if (x < 0 || x > (renderBuffer->width - 1)) return;
if (y < 0 || y > (renderBuffer->height - 1)) return;
@ -630,22 +620,22 @@ FILE_SCOPE inline void SIMDSetPixel(DTRRenderContext context, const i32 x, const
DTR_DEBUG_EP_TIMED_FUNCTION();
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
// 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.
f32 alpha = ((f32 *)&color)[3];
bool needGammaFix =
(alpha > 0.0f || alpha < (1.0f + COLOR_EPSILON)) && (colorSpace == ColorSpace_SRGB);
bool needGammaFix = (alpha > 0.0f || alpha < (1.0f + COLOR_EPSILON)) && (colorSpace == ColorSpace_SRGB);
if (needGammaFix) color = SIMDSRGB1ToLinearSpace(color);
// 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)];
__m128 src = _mm_set_ps(0, (f32)((srcPixel >> 0) & 0xFF),
(f32)((srcPixel >> 8) & 0xFF),
(f32)((srcPixel >> 16) & 0xFF));
__m128 src = _mm_set_ps(0,
(f32)((srcPixel >> 0) & 0xFF),
(f32)((srcPixel >> 8) & 0xFF),
(f32)((srcPixel >> 16) & 0xFF));
src = SIMDSRGB255ToLinearSpace1(src);
f32 invA = 1 - alpha;
@ -664,10 +654,12 @@ FILE_SCOPE inline void SIMDSetPixel(DTRRenderContext context, const i32 x, const
f32 destB = ((f32 *)&dest)[2];
u32 pixel = // ((u32)(destA) << 24 |
(u32)(destR) << 16 |
(u32)(destG) << 8 |
(u32)(destB) << 0;
(u32)(destR) << 16 |
(u32)(destG) << 8 |
(u32)(destB) << 0;
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
@ -716,7 +708,7 @@ FILE_SCOPE __m128 SIMDSampleTextureForTriangle(const DTRBitmap *const texture, c
// 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
// 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,
bool drawBoundingBox, bool drawBasis, bool drawVertexMarkers)
{
@ -733,10 +725,10 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const
{
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(context, 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(context, DqnV2i_2f(bounds.max.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.min.y), red);
DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.min.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.max.y), red);
DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.min.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.max.y), red);
DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.max.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.min.y), red);
DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.max.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.min.y), red);
}
// 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;
DqnV4 coordSysColor = DqnV4_4f(0, 1, 1, 1);
i32 axisLen = 50;
DTRRender_Line(context, DqnV2i_V2(origin),
DTRRender_Line(renderBuffer, DqnV2i_V2(origin),
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);
}
}
@ -765,40 +757,11 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const
for (i32 i = 0; i < pListSize; 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) \
do \
{ \
@ -817,18 +780,20 @@ FILE_SCOPE inline void SetCurrZDepth(DTRRenderContext context, i32 posX, i32 pos
DTRDebug_EndCycleCount(DTRDebugCycleCount_SIMD##type); \
} while (0)
FILE_SCOPE void
SIMDRasteriseTrianglePixel(DTRRenderContext context, const DTRBitmap *const texture, const i32 posX,
const i32 posY, const i32 maxX, const DqnV2 uv1, const DqnV2 uv2SubUv1,
const DqnV2 uv3SubUv1, const __m128 simdColor, const __m128 triangleZ,
const __m128 signedArea, const __m128 invSignedAreaParallelogram_4x,
const f32 preserveAlpha, const bool ignoreLight, const __m128 p1Light,
const __m128 p2Light, const __m128 p3Light)
FILE_SCOPE void SIMDRasteriseTrianglePixel(DTRRenderBuffer *const renderBuffer,
const DTRBitmap *const texture, const i32 posX,
const i32 posY, const i32 maxX, const DqnV2 uv1,
const DqnV2 uv2SubUv1, const DqnV2 uv3SubUv1,
const __m128 simdColor, const __m128 triangleZ,
const __m128 signedArea,
const __m128 invSignedAreaParallelogram_4x)
{
DTRRenderBuffer *const renderBuffer = context.renderBuffer;
const __m128 ZERO_4X = _mm_set_ps1(0.0f);
const u32 IS_GREATER_MASK = 0xF;
const u32 zBufferPitch = renderBuffer->width;
const __m128 ZERO_4X = _mm_set_ps1(0.0f);
const u32 IS_GREATER_MASK = 0xF;
const u32 zBufferPitch = renderBuffer->width;
// TODO(doyle): Copy lighting work over. But not important since using this
// function causes performance problems.
// Rasterise buffer(X, Y) pixel
{
@ -838,51 +803,32 @@ SIMDRasteriseTrianglePixel(DTRRenderContext context, const DTRBitmap *const text
if ((isGreaterResult & IS_GREATER_MASK) == IS_GREATER_MASK && posX < maxX)
{
DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel);
__m128 barycentric = _mm_mul_ps(signedArea, invSignedAreaParallelogram_4x);
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
i32 zBufferIndex = posX + (posY * zBufferPitch);
f32 pixelZValue =
((f32 *)&barycentricZ)[0] + ((f32 *)&barycentricZ)[1] + ((f32 *)&barycentricZ)[2];
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
if (pixelZValue > currZValue)
{
__m128 barycentric = _mm_mul_ps(signedArea, invSignedAreaParallelogram_4x);
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
f32 pixelZDepth = ((f32 *)&barycentricZ)[0] + ((f32 *)&barycentricZ)[1] +
((f32 *)&barycentricZ)[2];
i32 zBufferIndex = posX + (posY * zBufferPitch);
if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex])
__m128 finalColor = simdColor;
if (texture)
{
renderBuffer->zBuffer[zBufferIndex] = pixelZDepth;
__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(context, posX, posY, finalColor, ColorSpace_Linear);
__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1,
uv3SubUv1, barycentric);
finalColor = _mm_mul_ps(texSampledColor, simdColor);
}
SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear);
}
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 f32 lightIntensity1, const f32 lightIntensity2,
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_Preamble);
DTRRenderBuffer *const renderBuffer = context.renderBuffer;
////////////////////////////////////////////////////////////////////////////
// Convert color
////////////////////////////////////////////////////////////////////////////
@ -920,16 +864,16 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
////////////////////////////////////////////////////////////////////////////
// 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;
// SignedArea: _mm_set_ps(unused, p3, p2, p1) ie 0=p1, 1=p1, 2=p3, 3=unused
__m128 signedAreaPixel1 = _mm_set_ps1(0);
// __m128 signedAreaPixel2 = _mm_set_ps1(0);
__m128 signedAreaPixel1;
__m128 signedAreaPixel2;
__m128 signedAreaPixelDeltaX = _mm_set_ps1(0);
__m128 signedAreaPixelDeltaY = _mm_set_ps1(0);
__m128 invSignedAreaParallelogram_4x = _mm_set_ps1(0);
__m128 signedAreaPixelDeltaX;
__m128 signedAreaPixelDeltaY;
__m128 invSignedAreaParallelogram_4x;
__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);
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
{
@ -978,9 +922,13 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
const DqnV2 uv2SubUv1 = uv2 - uv1;
const DqnV2 uv3SubUv1 = uv3 - uv1;
#define UNROLL_LOOP 1
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Preamble);
#if UNROLL_LOOP
const u32 IS_GREATER_MASK = 0xF;
const u32 zBufferPitch = renderBuffer->width;
#endif
////////////////////////////////////////////////////////////////////////////
// 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)
{
__m128 signedArea1 = signedAreaPixel1;
// __m128 signedArea2 = signedAreaPixel2;
__m128 signedArea2 = signedAreaPixel2;
for (i32 bufferX = min.x; bufferX < max.x; bufferX += NUM_X_PIXELS_TO_SIMD)
{
#if UNROLL_LOOP
// Rasterise buffer(X, Y) pixel
{
__m128 checkArea = signedArea1;
@ -1007,31 +956,20 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
__m128 barycentric = _mm_mul_ps(checkArea, invSignedAreaParallelogram_4x);
__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)[2];
i32 zBufferIndex = posX + (posY * zBufferPitch);
if (context.multithread)
{
bool currLockValue;
do
{
currLockValue = (bool)context.api->AtomicCompareSwap(
(u32 *)&renderBuffer->pixelLockTable[zBufferIndex], (u32) true,
(u32) false);
} while (currLockValue != false);
}
if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex])
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
if (pixelZValue > currZValue)
{
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
__m128 finalColor = simdColor;
renderBuffer->zBuffer[zBufferIndex] = pixelZDepth;
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 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);
@ -1041,34 +979,91 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
_mm_add_ps(barycentricLight3,
_mm_add_ps(barycentricLight1, barycentricLight2));
finalColor = _mm_mul_ps(finalColor, light);
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);
__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
finalColor = _mm_mul_ps(texSampledColor, finalColor);
}
SIMDSetPixel(context, posX, posY, finalColor, ColorSpace_Linear);
SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear);
}
renderBuffer->pixelLockTable[zBufferIndex] = false;
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel);
}
signedArea1 = _mm_add_ps(signedArea1, signedAreaPixelDeltaX);
}
// Rasterise buffer(X + 1, Y) pixel
{
__m128 checkArea = signedArea2;
__m128 isGreater = _mm_cmpge_ps(checkArea, ZERO_4X);
i32 isGreaterResult = _mm_movemask_ps(isGreater);
i32 posX = bufferX + 1;
i32 posY = bufferY;
if ((isGreaterResult & IS_GREATER_MASK) == IS_GREATER_MASK && posX < max.x)
{
__m128 barycentric = _mm_mul_ps(checkArea, invSignedAreaParallelogram_4x);
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
i32 zBufferIndex = posX + (posY * zBufferPitch);
f32 pixelZValue = ((f32 *)&barycentricZ)[0] +
((f32 *)&barycentricZ)[1] +
((f32 *)&barycentricZ)[2];
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
if (pixelZValue > currZValue)
{
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
__m128 finalColor = simdColor;
if (!ignoreLight)
{
__m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]);
__m128 barycentricB_4x = _mm_set_ps1(((f32 *)&barycentric)[1]);
__m128 barycentricC_4x = _mm_set_ps1(((f32 *)&barycentric)[2]);
__m128 barycentricLight1 = _mm_mul_ps(p1Light, barycentricA_4x);
__m128 barycentricLight2 = _mm_mul_ps(p2Light, barycentricB_4x);
__m128 barycentricLight3 = _mm_mul_ps(p3Light, barycentricC_4x);
__m128 light =
_mm_add_ps(barycentricLight3,
_mm_add_ps(barycentricLight1, barycentricLight2));
finalColor = _mm_mul_ps(finalColor, light);
((f32 *)&finalColor)[3] = preserveAlpha;
}
if (texture)
{
__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
finalColor = _mm_mul_ps(texSampledColor, finalColor);
}
SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear);
}
}
signedArea2 = _mm_add_ps(signedArea2, signedAreaPixelDeltaX);
}
#else
SIMDRasteriseTrianglePixel(renderBuffer, texture, bufferX, bufferY, max.x, uv1, uv2SubUv1,
uv3SubUv1, simdColor, triangleZ, signedArea1,
invSignedAreaParallelogram_4x);
SIMDRasteriseTrianglePixel(renderBuffer, texture, bufferX + 1, bufferY, max.x, uv1, uv2SubUv1,
uv3SubUv1, simdColor, triangleZ, signedArea2,
invSignedAreaParallelogram_4x);
signedArea1 = _mm_add_ps(signedArea1, signedAreaPixelDeltaX);
signedArea2 = _mm_add_ps(signedArea2, signedAreaPixelDeltaX);
#endif
}
signedAreaPixel1 = _mm_add_ps(signedAreaPixel1, signedAreaPixelDeltaY);
// signedAreaPixel2 = _mm_add_ps(signedAreaPixel2, signedAreaPixelDeltaY);
signedAreaPixel2 = _mm_add_ps(signedAreaPixel2, signedAreaPixelDeltaY);
}
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Rasterise);
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle);
}
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 f32 lightIntensity1, const f32 lightIntensity2,
const f32 lightIntensity3, const bool ignoreLight,
@ -1076,6 +1071,7 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
const DqnV2i max)
{
DTR_DEBUG_EP_TIMED_FUNCTION();
#define DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(type) \
do \
{ \
@ -1095,9 +1091,8 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
} while (0)
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
////////////////////////////////////////////////////////////////////////////
@ -1151,39 +1146,75 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
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);
f32 barycentricA = signedArea1 * invSignedAreaParallelogram;
f32 barycentricB = signedArea2 * invSignedAreaParallelogram;
f32 barycentricC = signedArea3 * invSignedAreaParallelogram;
i32 zBufferIndex = bufferX + (bufferY * zBufferPitch);
if (context.multithread)
{
bool currLockValue;
do
{
currLockValue = (bool)context.api->AtomicCompareSwap(
(u32 *)&renderBuffer->pixelLockTable[zBufferIndex], (u32) true,
(u32) false);
} while (currLockValue != false);
}
f32 pixelZValue = p1.z + (barycentricB * (p2SubP1.z)) + (barycentricC * (p3SubP1.z));
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
DQN_ASSERT(zBufferIndex < (renderBuffer->width * renderBuffer->height));
f32 pixelZDepth =
p1.z + (barycentricB * (p2SubP1.z)) + (barycentricC * (p3SubP1.z));
if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex])
if (pixelZValue >= currZValue)
{
DqnV4 finalColor = color;
renderBuffer->zBuffer[zBufferIndex] = pixelZDepth;
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
DqnV4 finalColor = color;
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)
{
DqnV3 light = (p1Light * barycentricA) + (p2Light * barycentricB) +
f32 barycentricA = signedArea1 * invSignedAreaParallelogram;
DqnV3 light = (p1Light * barycentricA) + (p2Light * barycentricB) +
(p3Light * barycentricC);
finalColor.rgb *= light;
DQN_ASSERT(finalColor.x >= 0);
}
DQN_ASSERT(finalColor.x >= 0);
if (texture)
{
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 = DTRRender_SRGB1ToLinearSpaceV4(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);
}
@ -1262,14 +1296,11 @@ DqnMat4 GLViewport(f32 x, f32 y, f32 width, f32 height)
return result;
}
FILE_SCOPE void
TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting, DqnV3 p1, DqnV3 p2,
DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture,
DqnV4 color,
const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform())
FILE_SCOPE void TexturedTriangleInternal(DTRRenderBuffer *const renderBuffer,
RenderLightInternal lighting, DqnV3 p1, DqnV3 p2, DqnV3 p3,
DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture,
DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform())
{
DTRRenderBuffer *renderBuffer = context.renderBuffer;
////////////////////////////////////////////////////////////////////////////
// Transform vertexes p1, p2, p3 inplace
////////////////////////////////////////////////////////////////////////////
@ -1324,14 +1355,14 @@ TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting,
////////////////////////////////////////////////////////////////////////////
// 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);
}
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);
}
@ -1344,7 +1375,7 @@ TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting,
bool drawBasis = false;
bool drawVertexMarkers = false;
DebugRenderMarkers(context, pList, DQN_ARRAY_COUNT(pList), transform, drawBoundingBox,
DebugRenderMarkers(renderBuffer, pList, DQN_ARRAY_COUNT(pList), transform, drawBoundingBox,
drawBasis, drawVertexMarkers);
}
}
@ -1355,51 +1386,20 @@ FILE_SCOPE RenderLightInternal NullRenderLightInternal()
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,
DTRBitmap *const texture, DqnV4 color,
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);
}
typedef struct RenderMeshJob
void DTRRender_Mesh(DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh,
DTRRenderLight lighting, const DqnV3 pos,
const DTRRenderTransform transform)
{
DTRRenderContext context;
DTRBitmap *tex;
RenderLightInternal lighting;
DqnV3 v1;
DqnV3 v2;
DqnV3 v3;
DqnV2 uv1;
DqnV2 uv2;
DqnV2 uv3;
DqnV4 color;
} RenderMeshJob;
void MultiThreadedRenderMesh(PlatformJobQueue *const queue, void *const userData)
{
if (!queue || !userData)
{
DQN_ASSERT(DQN_INVALID_CODE_PATH);
return;
}
RenderMeshJob *job = (RenderMeshJob *)userData;
TexturedTriangleInternal(job->context, job->lighting, job->v1, job->v2, job->v3, job->uv1,
job->uv2, job->uv3, job->tex, job->color);
}
void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue, DTRMesh *const mesh,
DTRRenderLight lighting, const DqnV3 pos, const DTRRenderTransform transform)
{
DqnMemStack *const tempStack = context.tempStack;
DTRRenderBuffer *const renderBuffer = context.renderBuffer;
PlatformAPI *const api = context.api;
if (!mesh || !renderBuffer || !tempStack || !api || !jobQueue) return;
if (!mesh) return;
DqnMat4 viewPModelViewProjection = {};
{
@ -1501,8 +1501,7 @@ void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue,
DqnV2 uv2 = mesh->texUV[uv2Index].xy;
DqnV2 uv3 = mesh->texUV[uv3Index].xy;
DqnV4 color = lighting.color;
DqnV4 color = lighting.color;
RenderLightInternal lightingInternal = {};
lightingInternal.mode = lighting.mode;
lightingInternal.vector = lighting.vector;
@ -1512,92 +1511,43 @@ void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue,
lightingInternal.numNormals = 3;
bool DEBUG_NO_TEX = false;
if (context.multithread)
if (DTR_DEBUG && DEBUG_NO_TEX)
{
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)
{
jobData->tex = NULL;
}
else
{
jobData->tex = &mesh->tex;
}
PlatformJob renderJob = {};
renderJob.callback = MultiThreadedRenderMesh;
renderJob.userData = jobData;
while (!api->QueueAddJob(jobQueue, renderJob))
{
api->QueueTryExecuteNextJob(jobQueue);
}
}
else
{
// TODO(doyle): Allocation error
DQN_ASSERT(DQN_INVALID_CODE_PATH);
}
TexturedTriangleInternal(renderBuffer, lightingInternal, v1.xyz, v2.xyz, v3.xyz, uv1,
uv2, uv3, NULL, color);
}
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);
}
TexturedTriangleInternal(renderBuffer, lightingInternal, v1.xyz, v2.xyz, v3.xyz, uv1,
uv2, uv3, &mesh->tex, color);
}
bool DEBUG_WIREFRAME = false;
if (DTR_DEBUG && DEBUG_WIREFRAME)
{
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(context, DqnV2i_V2(v2.xy), DqnV2i_V2(v3.xy), wireColor);
DTRRender_Line(context, DqnV2i_V2(v3.xy), DqnV2i_V2(v1.xy), wireColor);
DTRRender_Line(renderBuffer, DqnV2i_V2(v1.xy), DqnV2i_V2(v2.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)
{
// 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)
void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3,
DqnV4 color, const DTRRenderTransform transform)
{
const DqnV2 NO_UV = {};
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);
}
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)
{
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!bitmap || !bitmap->memory || !renderBuffer) return;
DTR_DEBUG_EP_TIMED_FUNCTION();
@ -1771,7 +1721,7 @@ void DTRRender_Bitmap(DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 p
blend.g *= color.g;
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 drawVertexMarkers = true;
DebugRenderMarkers(context, pList, RECT_PLIST_SIZE, transform, drawBoundingBox,
DebugRenderMarkers(renderBuffer, pList, RECT_PLIST_SIZE, transform, drawBoundingBox,
drawBasis, drawVertexMarkers);
}
}
void DTRRender_Clear(DTRRenderContext context, DqnV3 color)
void DTRRender_Clear(DTRRenderBuffer *const renderBuffer,
DqnV3 color)
{
DTRRenderBuffer *renderBuffer = context.renderBuffer;
if (!renderBuffer) return;
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
#include "dqn.h"
#include "DTRendererPlatform.h"
#define DTRRENDER_INV_255 1.0f/255.0f
typedef struct DTRRenderBuffer DTRRenderBuffer;
typedef struct DTRBitmap DTRBitmap;
////////////////////////////////////////////////////////////////////////////////////////////////////
@ -16,11 +16,9 @@ typedef struct DTRRenderBuffer
i32 width;
i32 height;
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;
@ -76,25 +74,15 @@ typedef struct DTRRenderLight
DqnV4 color;
} 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
// 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_Line (DTRRenderContext context, DqnV2i a, DqnV2i b, DqnV4 color);
void DTRRender_Rectangle (DTRRenderContext context, 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_Triangle (DTRRenderContext context, 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_Bitmap (DTRRenderContext context, 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_Text (DTRRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1);
void DTRRender_Line (DTRRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color);
void DTRRender_Rectangle (DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform());
void DTRRender_Mesh (DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh, DTRRenderLight lighting, const DqnV3 pos, const DTRRenderTransform transform);
void DTRRender_Triangle (DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform());
void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform());
void DTRRender_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 (DTRRenderBuffer *const renderBuffer, DqnV3 color);
#endif

View File

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

View File

@ -16,11 +16,6 @@ if %errorlevel%==0 (
ctags -R
)
where /q gtags
if %errorlevel%==0 (
gtags
)
set ProjectName=dtrenderer
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 MD use dynamic runtime library
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 instead of generating a call to external library (i.e. CRT).
REM Zi enables debug data, Z7 combines the debug files into one.
@ -43,47 +39,28 @@ REM wd4100 unused argument parameters
REM wd4201 nonstandard extension used: nameless struct/union
REM wd4189 local variable is initialised but not referenced
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 Win32Flags=/FmWin32DTRenderer /FeWin32DTRenderer
REM Link libraries
set LinkLibraries=user32.lib kernel32.lib gdi32.lib
REM incremental:no, turn incremental builds off
REM opt:ref, try to remove functions from libs that are not referenced at all
set LinkFlags=-incremental:no -opt:ref -subsystem:WINDOWS -machine:x64 -nologo
set DebugMode=1
if %DebugMode%==1 goto :DebugFlags
goto :ReleaseFlags
:DebugFlags
REM Od disables optimisations
REM RTC1 runtime error checks, only possible with optimisations disabled
set CompileFlags=%CompileFlags% -Od -RTC1
goto compile
:ReleaseFlags
REM opt:icf, COMDAT folding for debugging release build
REM DEBUG:[FULL|NONE] enforce debugging for release build
set CompileFlags=%CompileFlags% -O2
set LinkFlags=%LinkFlags%
REM ////////////////////////////////////////////////////////////////////////////
REM Compile
REM ////////////////////////////////////////////////////////////////////////////
:compile
REM Clean time necessary for hours <10, which produces H:MM:SS.SS where the
REM 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
set LinkLibraries=user32.lib kernel32.lib gdi32.lib
REM incremental:no, turn incremental builds off
REM opt:ref, try to remove functions from libs that are not referenced at all
set LinkFlags=-incremental:no -opt:ref -subsystem:WINDOWS -machine:x64 -nologo
REM ////////////////////////////////////////////////////////////////////////////
REM Compile
REM ////////////////////////////////////////////////////////////////////////////
del *.pdb >NUL 2>NUL
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%
cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags%

3202
src/dqn.h

File diff suppressed because it is too large Load Diff