/**
* a dummy window is invisible with message loop
*/
// 内存泄漏检测
// 在需要检测的地方放置语句:
// _CrtDumpMemoryLeaks();
// 以下3句的次序不能改变
#define _CRTDBG_MAP_ALLOC
#include<stdlib.h>
#include<crtdbg.h>
#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <assert.h>
#define DUMMY_WND_STYLE (WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_POPUP)
#define DUMMY_WND_WIDTH 500
#define DUMMY_WND_HEIGHT 400
static int loopFlag = 1;
// First of all we should have a backend buffer (a block of pixels array).
// We must ensure this backend is thread safe since we want to fill the OGL
// frame data into it and then flush it onto the target device.
// Typically this backend buffer is a DIBSection with a valid HDC that is
// compatiable with target.
typedef struct
{
CRITICAL_SECTION __lock;
int updateId;
HWND dummyWnd;
/// DIBSection bmp;
} BackendBuffer, *BACKEND;
BACKEND BackendBufferCreate (HWND dummyWnd)
{
BACKEND backend = (BACKEND) malloc(sizeof(BackendBuffer));
InitializeCriticalSection(&backend->__lock);
backend->updateId = 0;
backend->dummyWnd = dummyWnd;
printf("BackendBufferCreate(): Prepare OGL context\n");
// Create DIBSection for backend from dummyWnd PixlFormat
// ...
printf("BackendBufferCreate(): Create DIBSection for backend\n");
return backend;
}
void BackendBufferDelete (BACKEND backend)
{
DeleteCriticalSection(&backend->__lock);
// Free DIBSection for backend...
free(backend);
}
typedef void (* pfcb_oglRenderFunc) (void *backend);
static void oglRenderBackend (void *param)
{
BACKEND backend = (BACKEND) param;
printf("ogl Render on backend: %d\n", backend->updateId);
// Fill in DIBSection of backend...
// ...readPixels(...);
// modify updateId that means the backend has been changed
backend->updateId++;
if (backend->updateId > 100000000) {
backend->updateId = 0;
}
}
BOOL BackendBufferUpdate (BACKEND backend, pfcb_oglRenderFunc oglRenderFunc)
{
if (TryEnterCriticalSection(&backend->__lock)) {
oglRenderFunc(backend);
LeaveCriticalSection(&backend->__lock);
// We notice caller update successfully
return TRUE;
} else {
// Something error
return FALSE;
}
}
typedef struct
{
int updateId;
BACKEND backend;
// target device handle: can be HWND or FILE, ...
HWND targetWnd;
} TargetSurface, *TARGET;
TARGET TargetSurfaceCreate (HWND targetWnd, HWND hwndBackend)
{
TARGET tgt = (TargetSurface*) malloc(sizeof(TargetSurface));
tgt->updateId = -1;
tgt->backend = BackendBufferCreate(hwndBackend);
tgt->targetWnd = targetWnd;
return tgt;
}
void TargetSurfaceDelete (TARGET tgt)
{
BackendBufferDelete(tgt->backend);
free(tgt);
}
// Below function should be called in OnDraw() or onRefreshEvent()
//
void TargetSurfaceUpdate (TARGET tgt)
{
if (tgt->updateId != tgt->backend->updateId) {
// Only update target when updateId not equal
if (TryEnterCriticalSection(&tgt->backend->__lock)) {
// Do update target device job here...BitBlt(...);
Sleep(20); // We suppose it will cost me 20 msec to update device
printf("TargetSurface has been updated:%d\n", tgt->updateId);
// Set update target ok
tgt->updateId = tgt->backend->updateId;
LeaveCriticalSection(&tgt->backend->__lock);
}
}
}
static void Fire_OnDraw(TARGET target)
{
TargetSurfaceUpdate(target);
}
static void renderOGLScene (TARGET target)
{
// target can be convey to OGL render engine
// OGL render engine can change
printf("renderOGLScene use target... \n");
if (BackendBufferUpdate(target->backend, oglRenderBackend)) {
// Fire_OnDraw will trigger systen,
// and system will call TargetSurfaceUpdate by sequence
Fire_OnDraw(target);
}
// We suppose it takes 10 ms to render OGL
Sleep(10);
}
static void renderThreadFunc (void *param)
{
MSG msg;
TARGET target = (TARGET) param;
while (loopFlag) {
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
printf("renderThreadFunc recv a WM_QUIT message\n");
break ;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
renderOGLScene(target);
}
}
printf("renderThreadFunc quit\n");
}
HWND createDummyWindow (int width, int height)
{
HWND hwndDummy = CreateWindowA("STATIC",
"DummyWindowForOpenGLOffScreen",
DUMMY_WND_STYLE,
0, 0, width, height,
0, 0, 0, 0);
return hwndDummy;
}
UINT createRenderThread (void *param)
{
UINT threadId = 0;
HANDLE threadHandle = (HANDLE)_beginthreadex(0, 0,
(unsigned (__stdcall *)(void *))renderThreadFunc, param, 0, &threadId);
assert(threadHandle);
CloseHandle(threadHandle);
return threadId;
}
int main ()
{
BOOL ret;
HWND hwndDummy;
UINT threadId;
TARGET target;
hwndDummy = createDummyWindow(DUMMY_WND_WIDTH, DUMMY_WND_HEIGHT);
assert(hwndDummy);
printf("Create dummy window for OGL\n");
printf("Then create a target for drawing\n");
target = TargetSurfaceCreate((HWND)123, hwndDummy);
assert(target);
threadId = createRenderThread(target);
printf("Create OGL render thread\n");
// analogy to do somthing
Sleep(10000);
printf("Notify RenderThread to quit\n");
ret = PostThreadMessage(threadId, WM_QUIT, 0, 0);
assert(ret);
// analogy to do somthing
Sleep(10000);
printf("Main app shutdown\n");
TargetSurfaceDelete(target);
_CrtDumpMemoryLeaks();
exit(0);
}
* a dummy window is invisible with message loop
*/
// 内存泄漏检测
// 在需要检测的地方放置语句:
// _CrtDumpMemoryLeaks();
// 以下3句的次序不能改变
#define _CRTDBG_MAP_ALLOC
#include<stdlib.h>
#include<crtdbg.h>
#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <assert.h>
#define DUMMY_WND_STYLE (WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_POPUP)
#define DUMMY_WND_WIDTH 500
#define DUMMY_WND_HEIGHT 400
static int loopFlag = 1;
// First of all we should have a backend buffer (a block of pixels array).
// We must ensure this backend is thread safe since we want to fill the OGL
// frame data into it and then flush it onto the target device.
// Typically this backend buffer is a DIBSection with a valid HDC that is
// compatiable with target.
typedef struct
{
CRITICAL_SECTION __lock;
int updateId;
HWND dummyWnd;
/// DIBSection bmp;
} BackendBuffer, *BACKEND;
BACKEND BackendBufferCreate (HWND dummyWnd)
{
BACKEND backend = (BACKEND) malloc(sizeof(BackendBuffer));
InitializeCriticalSection(&backend->__lock);
backend->updateId = 0;
backend->dummyWnd = dummyWnd;
printf("BackendBufferCreate(): Prepare OGL context\n");
// Create DIBSection for backend from dummyWnd PixlFormat
// ...
printf("BackendBufferCreate(): Create DIBSection for backend\n");
return backend;
}
void BackendBufferDelete (BACKEND backend)
{
DeleteCriticalSection(&backend->__lock);
// Free DIBSection for backend...
free(backend);
}
typedef void (* pfcb_oglRenderFunc) (void *backend);
static void oglRenderBackend (void *param)
{
BACKEND backend = (BACKEND) param;
printf("ogl Render on backend: %d\n", backend->updateId);
// Fill in DIBSection of backend...
// ...readPixels(...);
// modify updateId that means the backend has been changed
backend->updateId++;
if (backend->updateId > 100000000) {
backend->updateId = 0;
}
}
BOOL BackendBufferUpdate (BACKEND backend, pfcb_oglRenderFunc oglRenderFunc)
{
if (TryEnterCriticalSection(&backend->__lock)) {
oglRenderFunc(backend);
LeaveCriticalSection(&backend->__lock);
// We notice caller update successfully
return TRUE;
} else {
// Something error
return FALSE;
}
}
typedef struct
{
int updateId;
BACKEND backend;
// target device handle: can be HWND or FILE, ...
HWND targetWnd;
} TargetSurface, *TARGET;
TARGET TargetSurfaceCreate (HWND targetWnd, HWND hwndBackend)
{
TARGET tgt = (TargetSurface*) malloc(sizeof(TargetSurface));
tgt->updateId = -1;
tgt->backend = BackendBufferCreate(hwndBackend);
tgt->targetWnd = targetWnd;
return tgt;
}
void TargetSurfaceDelete (TARGET tgt)
{
BackendBufferDelete(tgt->backend);
free(tgt);
}
// Below function should be called in OnDraw() or onRefreshEvent()
//
void TargetSurfaceUpdate (TARGET tgt)
{
if (tgt->updateId != tgt->backend->updateId) {
// Only update target when updateId not equal
if (TryEnterCriticalSection(&tgt->backend->__lock)) {
// Do update target device job here...BitBlt(...);
Sleep(20); // We suppose it will cost me 20 msec to update device
printf("TargetSurface has been updated:%d\n", tgt->updateId);
// Set update target ok
tgt->updateId = tgt->backend->updateId;
LeaveCriticalSection(&tgt->backend->__lock);
}
}
}
static void Fire_OnDraw(TARGET target)
{
TargetSurfaceUpdate(target);
}
static void renderOGLScene (TARGET target)
{
// target can be convey to OGL render engine
// OGL render engine can change
printf("renderOGLScene use target... \n");
if (BackendBufferUpdate(target->backend, oglRenderBackend)) {
// Fire_OnDraw will trigger systen,
// and system will call TargetSurfaceUpdate by sequence
Fire_OnDraw(target);
}
// We suppose it takes 10 ms to render OGL
Sleep(10);
}
static void renderThreadFunc (void *param)
{
MSG msg;
TARGET target = (TARGET) param;
while (loopFlag) {
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
printf("renderThreadFunc recv a WM_QUIT message\n");
break ;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
} else {
renderOGLScene(target);
}
}
printf("renderThreadFunc quit\n");
}
HWND createDummyWindow (int width, int height)
{
HWND hwndDummy = CreateWindowA("STATIC",
"DummyWindowForOpenGLOffScreen",
DUMMY_WND_STYLE,
0, 0, width, height,
0, 0, 0, 0);
return hwndDummy;
}
UINT createRenderThread (void *param)
{
UINT threadId = 0;
HANDLE threadHandle = (HANDLE)_beginthreadex(0, 0,
(unsigned (__stdcall *)(void *))renderThreadFunc, param, 0, &threadId);
assert(threadHandle);
CloseHandle(threadHandle);
return threadId;
}
int main ()
{
BOOL ret;
HWND hwndDummy;
UINT threadId;
TARGET target;
hwndDummy = createDummyWindow(DUMMY_WND_WIDTH, DUMMY_WND_HEIGHT);
assert(hwndDummy);
printf("Create dummy window for OGL\n");
printf("Then create a target for drawing\n");
target = TargetSurfaceCreate((HWND)123, hwndDummy);
assert(target);
threadId = createRenderThread(target);
printf("Create OGL render thread\n");
// analogy to do somthing
Sleep(10000);
printf("Notify RenderThread to quit\n");
ret = PostThreadMessage(threadId, WM_QUIT, 0, 0);
assert(ret);
// analogy to do somthing
Sleep(10000);
printf("Main app shutdown\n");
TargetSurfaceDelete(target);
_CrtDumpMemoryLeaks();
exit(0);
}