首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

一个OpenGL后盾渲染的架构

2012-11-08 
一个OpenGL后台渲染的架构/** * a dummy window is invisible with message loop */// 内存泄漏检测// 在

一个OpenGL后台渲染的架构
/**
 * 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);
}

热点排行