Add dll reloading

This commit is contained in:
Doyle Thai 2017-05-08 22:59:44 +10:00
parent 7f62ce23d0
commit e6d198b232
8 changed files with 826 additions and 453 deletions

View File

@ -1,29 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26403.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "drenderer", "bin\drenderer.exe", "{25476A47-63FF-426D-A4A2-73AB789B9916}"
ProjectSection(DebuggerProjectSystem) = preProject
PortSupplier = 00000000-0000-0000-0000-000000000000
Executable = C:\git\drenderer\bin\drenderer.exe
RemoteMachine = THAI-PC
StartingDirectory = C:\git\drenderer\bin
Environment = Default
LaunchingEngine = 00000000-0000-0000-0000-000000000000
UseLegacyDebugEngines = No
LaunchSQLEngine = No
AttachLaunchAction = No
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{25476A47-63FF-426D-A4A2-73AB789B9916}.Release|x64.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -1,6 +1,22 @@
#include "DRenderer.h"
#include "DRendererPlatform.h" #include "DRendererPlatform.h"
void DR_Update(PlatformRenderBuffer *const renderBuffer, extern "C" void DR_Update(PlatformRenderBuffer *const renderBuffer,
PlatformInput *const input, PlatformMemory *const memory) PlatformInput *const input,
PlatformMemory *const memory)
{ {
u32 *bitmapPtr = (u32 *)renderBuffer->memory;
for (i32 y = 0; y < renderBuffer->height; y++)
{
for (i32 x = 0; x < renderBuffer->width; x++)
{
u8 red = 255;
u8 green = 0;
u8 blue = 0;
u32 color = (red << 16) | (green << 8) | (blue << 0);
bitmapPtr[x + (y * renderBuffer->width)] = color;
}
}
} }

View File

@ -1,8 +1,7 @@
#ifndef DRENDERER_H #ifndef DRENDERER_H
#define DRENDERER_H #define DRENDERER_H
void DR_Update(struct PlatformRenderBuffer *const renderBuffer, typedef void DR_UpdateFunction(struct PlatformRenderBuffer *const renderBuffer,
struct PlatformInput *const input, struct PlatformInput *const input,
struct PlatformMemory *const memory); struct PlatformMemory *const memory);
#endif #endif

View File

@ -44,9 +44,6 @@ typedef struct PlatformInput
{ {
f32 deltaForFrame; f32 deltaForFrame;
bool loadNewRom;
wchar_t rom[260];
union { union {
KeyState key[key_count]; KeyState key[key_count];
struct struct
@ -91,6 +88,8 @@ typedef struct PlatformRenderBuffer
i32 width; i32 width;
i32 height; i32 height;
i32 bytesPerPixel; i32 bytesPerPixel;
// Pixel Format: XX RR GG BB
void *memory; void *memory;
} PlatformRenderBuffer; } PlatformRenderBuffer;

View File

@ -1,2 +1 @@
#include "..\DRenderer.cpp" #include "..\DRenderer.cpp"
#include "..\Win32DRenderer.cpp"

View File

@ -8,6 +8,7 @@
#define UNICODE #define UNICODE
#define _UNICODE #define _UNICODE
#include <Pathcch.h>
#include <Windows.h> #include <Windows.h>
typedef struct Win32RenderBitmap typedef struct Win32RenderBitmap
{ {
@ -22,33 +23,13 @@ typedef struct Win32RenderBitmap
FILE_SCOPE Win32RenderBitmap globalRenderBitmap; FILE_SCOPE Win32RenderBitmap globalRenderBitmap;
FILE_SCOPE bool globalRunning; FILE_SCOPE bool globalRunning;
FILE_SCOPE void Win32DisplayRenderBitmap(Win32RenderBitmap renderBitmap, typedef struct Win32ExternalCode
HDC deviceContext, LONG width,
LONG height)
{ {
HDC stretchDC = CreateCompatibleDC(deviceContext); HMODULE dll;
SelectObject(stretchDC, renderBitmap.handle); FILETIME lastWriteTime;
DQN_ASSERT(renderBitmap.width == width);
DQN_ASSERT(renderBitmap.height == height);
StretchBlt(deviceContext, 0, 0, width, height, stretchDC, 0, 0,
renderBitmap.width, renderBitmap.height, SRCCOPY);
// NOTE: Win32 AlphaBlend requires the RGB components to be premultiplied DR_UpdateFunction *DR_Update;
// with alpha. } Win32ExternalCode;
#if 0
BLENDFUNCTION blend = {};
blend.BlendOp = AC_SRC_OVER;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
if (!AlphaBlend(deviceContext, 0, 0, width, height, deviceContext, 0, 0,
width, height, blend))
{
OutputDebugString(L"AlphaBlend() failed.");
}
#endif
DeleteDC(stretchDC);
}
enum Win32Menu enum Win32Menu
{ {
@ -56,6 +37,62 @@ enum Win32Menu
Win32Menu_FileExit, Win32Menu_FileExit,
}; };
FILE_SCOPE void Win32DisplayRenderBitmap(Win32RenderBitmap renderBitmap,
HDC deviceContext, LONG width,
LONG height)
{
HDC stretchDC = CreateCompatibleDC(deviceContext);
SelectObject(stretchDC, renderBitmap.handle);
// DQN_ASSERT(renderBitmap.width == width);
// DQN_ASSERT(renderBitmap.height == height);
StretchBlt(deviceContext, 0, 0, width, height, stretchDC, 0, 0,
renderBitmap.width, renderBitmap.height, SRCCOPY);
DeleteDC(stretchDC);
}
FILETIME Win32GetLastWriteTime(const char *const srcName)
{
WIN32_FIND_DATA findData = {};
FILETIME lastWriteTime = {};
HANDLE findHandle = FindFirstFileA(srcName, &findData);
if (findHandle != INVALID_HANDLE_VALUE)
{
lastWriteTime = findData.ftLastWriteTime;
FindClose(findHandle);
}
return lastWriteTime;
}
FILE_SCOPE Win32ExternalCode Win32LoadExternalDLL(const char *const srcPath,
const char *const tmpPath,
const FILETIME lastWriteTime)
{
Win32ExternalCode result = {};
result.lastWriteTime = lastWriteTime;
CopyFile(srcPath, tmpPath, false);
DR_UpdateFunction *updateFunction = NULL;
result.dll = LoadLibraryA(tmpPath);
if (result.dll)
{
updateFunction =
(DR_UpdateFunction *)GetProcAddress(result.dll, "DR_Update");
if (updateFunction) result.DR_Update = updateFunction;
}
return result;
}
FILE_SCOPE void Win32UnloadExternalDLL(Win32ExternalCode *externalCode)
{
if (externalCode->dll) FreeLibrary(externalCode->dll);
externalCode->dll = NULL;
externalCode->DR_Update = NULL;
}
FILE_SCOPE void Win32CreateMenu(HWND window) FILE_SCOPE void Win32CreateMenu(HWND window)
{ {
HMENU menuBar = CreateMenu(); HMENU menuBar = CreateMenu();
@ -229,6 +266,35 @@ FILE_SCOPE void Win32ProcessMessages(HWND window, PlatformInput *input)
} }
} }
// 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, int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nShowCmd) LPWSTR lpCmdLine, int nShowCmd)
{ {
@ -268,14 +334,13 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
RECT rect = {}; RECT rect = {};
rect.right = MIN_WIDTH; rect.right = MIN_WIDTH;
rect.bottom = MIN_HEIGHT; rect.bottom = MIN_HEIGHT;
DWORD windowStyle = DWORD windowStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
AdjustWindowRect(&rect, windowStyle, true); AdjustWindowRect(&rect, windowStyle, true);
HWND mainWindow = CreateWindowExW( HWND mainWindow = CreateWindowExW(
WS_EX_COMPOSITED, wc.lpszClassName, L"DRenderer", windowStyle, 0, wc.lpszClassName, L"DRenderer", windowStyle, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, nullptr,
rect.bottom - rect.top, nullptr, nullptr, hInstance, nullptr); nullptr, hInstance, nullptr);
if (!mainWindow) if (!mainWindow)
{ {
@ -291,11 +356,6 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
header.biPlanes = 1; header.biPlanes = 1;
header.biBitCount = 32; header.biBitCount = 32;
header.biCompression = BI_RGB; // uncompressed bitmap header.biCompression = BI_RGB; // uncompressed bitmap
header.biSizeImage = 0;
header.biXPelsPerMeter = 0;
header.biYPelsPerMeter = 0;
header.biClrUsed = 0;
header.biClrImportant = 0;
globalRenderBitmap.info.bmiHeader = header; globalRenderBitmap.info.bmiHeader = header;
globalRenderBitmap.width = header.biWidth; globalRenderBitmap.width = header.biWidth;
@ -315,6 +375,26 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
DqnWin32_DisplayLastError("CreateDIBSection() failed"); DqnWin32_DisplayLastError("CreateDIBSection() failed");
return -1; return -1;
} }
////////////////////////////////////////////////////////////////////////////
// Make DLL Path
////////////////////////////////////////////////////////////////////////////
Win32ExternalCode dllCode = {};
char dllPath[MAX_PATH] = {};
char dllTmpPath[MAX_PATH] = {};
{
char exeDir[MAX_PATH] = {};
i32 lastSlashIndex =
Win32GetModuleDirectory(exeDir, DQN_ARRAY_COUNT(exeDir));
DQN_ASSERT(lastSlashIndex + 1 < DQN_ARRAY_COUNT(exeDir));
exeDir[lastSlashIndex + 1] = 0;
u32 numCopied = Dqn_sprintf(dllPath, "%s%s", exeDir, "drenderer.dll");
DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllPath));
numCopied =
Dqn_sprintf(dllTmpPath, "%s%s", exeDir, "drenderer_temp.dll");
DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllPath));
}
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Update Loop // Update Loop
@ -328,13 +408,20 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
f64 frameTimeInS = 0.0f; f64 frameTimeInS = 0.0f;
globalRunning = true; globalRunning = true;
SetWindowTextA(mainWindow, "test");
while (globalRunning) while (globalRunning)
{ {
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// Update State // Update State
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
f64 startFrameTimeInS = DqnTime_NowInS(); f64 startFrameTimeInS = DqnTime_NowInS();
FILETIME lastWriteTime = Win32GetLastWriteTime(dllPath);
if (CompareFileTime(&lastWriteTime, &dllCode.lastWriteTime) != 0)
{
Win32UnloadExternalDLL(&dllCode);
dllCode = Win32LoadExternalDLL(dllPath, dllTmpPath, lastWriteTime);
}
{ {
PlatformInput platformInput = {}; PlatformInput platformInput = {};
platformInput.deltaForFrame = (f32)frameTimeInS; platformInput.deltaForFrame = (f32)frameTimeInS;
@ -345,7 +432,12 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
platformBuffer.height = globalRenderBitmap.height; platformBuffer.height = globalRenderBitmap.height;
platformBuffer.width = globalRenderBitmap.width; platformBuffer.width = globalRenderBitmap.width;
platformBuffer.bytesPerPixel = globalRenderBitmap.bytesPerPixel; platformBuffer.bytesPerPixel = globalRenderBitmap.bytesPerPixel;
DR_Update(&platformBuffer, &platformInput, &platformMemory);
if (dllCode.DR_Update)
{
dllCode.DR_Update(&platformBuffer, &platformInput,
&platformMemory);
}
} }
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
@ -386,7 +478,6 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
Dqn_sprintf(windowTitleBuffer, "drenderer - dev - %5.2f ms/f", Dqn_sprintf(windowTitleBuffer, "drenderer - dev - %5.2f ms/f",
msPerFrame); msPerFrame);
SetWindowTextA(mainWindow, windowTitleBuffer); SetWindowTextA(mainWindow, windowTitleBuffer);
#endif
} }
return 0; return 0;

View File

@ -37,12 +37,9 @@ 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=-EHa- -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -Od -FAsc set CompileFlags=-EHa- -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -Od -FAsc
set Defines= set DLLFlags=/Fm%ProjectName% /Fo%ProjectName% /Fa%ProjectName% /Fe%ProjectName%
set Win32Flags=/FmWin32DRenderer /FeWin32DRenderer
REM //////////////////////////////////////////////////////////////////////////// set TimeStamp=%date:~10,4%%date:~7,2%%date:~4,2%_%time:~0,2%%time:~3,2%%time:~6,2%
REM Include Directories/Link Libraries
REM ////////////////////////////////////////////////////////////////////////////
set IncludeFiles=
REM Link libraries REM Link libraries
set LinkLibraries=user32.lib kernel32.lib gdi32.lib set LinkLibraries=user32.lib kernel32.lib gdi32.lib
@ -54,9 +51,9 @@ set LinkFlags=-incremental:no -opt:ref -subsystem:WINDOWS -machine:x64 -nologo
REM //////////////////////////////////////////////////////////////////////////// REM ////////////////////////////////////////////////////////////////////////////
REM Compile REM Compile
REM //////////////////////////////////////////////////////////////////////////// REM ////////////////////////////////////////////////////////////////////////////
cl %CompileFlags% %Defines% ..\src\UnityBuild\UnityBuild.cpp %IncludeFiles% /link %LinkLibraries% %LinkFlags% /out:%ProjectName%.exe del *.pdb >NUL 2>NUL
REM cl %CompileFlags% /P %Defines% ..\src\UnityBuild\UnityBuild.cpp %IncludeFiles% cl %CompileFlags% %Win32Flags% ..\src\Win32DRenderer.cpp /link %LinkLibraries% %LinkFlags%
cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link /PDB:%ProjectName%_%TimeStamp%.pdb /export:DR_Update %LinkFlags%
popd popd
set LastError=%ERRORLEVEL% set LastError=%ERRORLEVEL%
ctime -end %ProjectName%.ctm %LastError% ctime -end %ProjectName%.ctm %LastError%

1035
src/dqn.h

File diff suppressed because it is too large Load Diff