here is the test source if someone is interested to try it
change “mode” to select among the 3 cases i mentioned - see the comment
ah, also “start” is the program entry point (i set that in the linker options). you can rename it to WinMain or whatever
#include <stdio.h>
#define INITGUID
#include <windows.h>
#include <GL/gl.h>
#include <d3d11.h>
static LRESULT CALLBACK wnd_proc(HWND wnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg) {
case WM_PAINT: ValidateRect(wnd, NULL); return 0;
case WM_CLOSE: ExitProcess(0); return 0;
default: return DefWindowProcA(wnd, msg, wp, lp);
}
}
#define WIDTH 1024
#define HEIGHT 768
// 0 = gl_clear/gl_present, 1 = gl_clear/d3d_present, 2 = d3d_clear/d3d_present
int mode = 1;
void start()
{
// window
WNDCLASSA wc;
RECT rc;
HWND wnd;
// d3d
ID3D11Device *d3ddev;
ID3D11DeviceContext *d3dctx;
IDXGISwapChain *sc;
DXGI_SWAP_CHAIN_DESC scd;
ID3D11Texture2D *d3dbb;
ID3D11RenderTargetView *view;
// opengl
HDC dc;
PIXELFORMATDESCRIPTOR pfd;
int pf;
HGLRC ctx;
#define WGL_ACCESS_READ_WRITE_NV 0x0001
HANDLE (WINAPI *wglDXOpenDeviceNV)(void *dxDevice);
HANDLE (WINAPI *wglDXRegisterObjectNV)(HANDLE hDevice, void *dxObject, GLuint name, GLenum type, GLenum access);
BOOL (WINAPI *wglDXLockObjectsNV)(HANDLE hDevice, GLint count, HANDLE *hObjects);
BOOL (WINAPI *wglDXUnlockObjectsNV)(HANDLE hDevice, GLint count, HANDLE *hObjects);
HANDLE idev;
#define GL_READ_FRAMEBUFFER 0x8CA8
#define GL_DRAW_FRAMEBUFFER 0x8CA9
#define GL_RENDERBUFFER 0x8D41
#define GL_COLOR_ATTACHMENT0 0x8CE0
void (APIENTRY *glGenFramebuffers) (GLsizei n, GLuint *framebuffers);
void (APIENTRY *glBindFramebuffer) (GLenum target, GLuint framebuffer);
void (APIENTRY *glFramebufferRenderbuffer) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
void (APIENTRY *glGenRenderbuffers) (GLsizei n, GLuint *renderbuffers);
void (APIENTRY *glBindRenderbuffer) (GLenum target, GLuint renderbuffer);
void (APIENTRY *glRenderbufferStorage) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
GLenum (APIENTRY *glCheckFramebufferStatus) (GLenum target);
void (APIENTRY *glBlitFramebuffer) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
GLuint bb, fb;
HANDLE ibb;
// create windwo
memset(&wc, 0, sizeof(wc));
wc.lpfnWndProc = wnd_proc;
wc.lpszClassName = "test_wc";
wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
RegisterClassA(&wc);
rc.left = rc.top = 0;
rc.right = WIDTH;
rc.bottom = HEIGHT;
AdjustWindowRect(&rc, WS_CAPTION|WS_SYSMENU, FALSE);
wnd = CreateWindowExA(0, wc.lpszClassName, "window", WS_CAPTION|WS_SYSMENU, 0, 0, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, NULL, NULL);
ShowWindow(wnd, SW_SHOW);
if (mode) {
IDXGIFactory *factory;
IDXGIAdapter *adapter;
IDXGIOutput *output;
DXGI_OUTPUT_DESC od;
CreateDXGIFactory(&IID_IDXGIFactory, &factory);
factory->lpVtbl->EnumAdapters(factory, 0, &adapter);
adapter->lpVtbl->EnumOutputs(adapter, 0, &output);
output->lpVtbl->GetDesc(output, &od);
output->lpVtbl->Release(output);
// create d3d device
memset(&scd, 0, sizeof(scd));
scd.BufferDesc.Width = WIDTH;
scd.BufferDesc.Height = HEIGHT;
scd.BufferDesc.RefreshRate.Numerator = 60;
scd.BufferDesc.RefreshRate.Denominator = 1;
scd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
scd.SampleDesc.Count = 1;
scd.BufferUsage = DXGI_USAGE_BACK_BUFFER|DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.BufferCount = 1;
scd.OutputWindow = wnd;
scd.Windowed = TRUE;
D3D11CreateDeviceAndSwapChain(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, D3D11_CREATE_DEVICE_SINGLETHREADED,
NULL, 0, D3D11_SDK_VERSION, &scd, &sc, &d3ddev, NULL, &d3dctx);
sc->lpVtbl->GetBuffer(sc, 0, &IID_ID3D11Texture2D, (void **)&d3dbb);
if (mode > 1) {
D3D11_RENDER_TARGET_VIEW_DESC vd;
D3D11_VIEWPORT vp;
vd.Format = DXGI_FORMAT_UNKNOWN;
vd.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
vd.Texture2D.MipSlice = 0;
d3ddev->lpVtbl->CreateRenderTargetView(d3ddev, d3dbb, &vd, &view);
d3dctx->lpVtbl->OMSetRenderTargets(d3dctx, 1, &view, NULL);
vp.TopLeftX = vp.TopLeftY = 0;
vp.Width = WIDTH;
vp.Height = HEIGHT;
vp.MinDepth = 0;
vp.MaxDepth = 1;
d3dctx->lpVtbl->RSSetViewports(d3dctx, 1, &vp);
}
}
if (mode < 2) {
dc = GetDC(wnd);
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DEPTH_DONTCARE;
pf = ChoosePixelFormat(dc, &pfd);
SetPixelFormat(dc, pf, NULL);
ctx = wglCreateContext(dc);
wglMakeCurrent(dc, ctx);
glGetString(GL_RENDERER);
*(PROC *)&glGenRenderbuffers = wglGetProcAddress("glGenRenderbuffers");
*(PROC *)&glGenFramebuffers = wglGetProcAddress("glGenFramebuffers");
*(PROC *)&glBindFramebuffer = wglGetProcAddress("glBindFramebuffer");
*(PROC *)&glFramebufferRenderbuffer = wglGetProcAddress("glFramebufferRenderbuffer");
*(PROC *)&glCheckFramebufferStatus = wglGetProcAddress("glCheckFramebufferStatus");
*(PROC *)&glBindRenderbuffer = wglGetProcAddress("glBindRenderbuffer");
*(PROC *)&glRenderbufferStorage = wglGetProcAddress("glRenderbufferStorage");
*(PROC *)&glBlitFramebuffer = wglGetProcAddress("glBlitFramebuffer");
glGenFramebuffers(1, &fb);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fb);
glGenRenderbuffers(1, &bb);
if (mode) {
*(PROC *)&wglDXOpenDeviceNV = wglGetProcAddress("wglDXOpenDeviceNV");
*(PROC *)&wglDXRegisterObjectNV = wglGetProcAddress("wglDXRegisterObjectNV");
*(PROC *)&wglDXLockObjectsNV = wglGetProcAddress("wglDXLockObjectsNV");
*(PROC *)&wglDXUnlockObjectsNV = wglGetProcAddress("wglDXUnlockObjectsNV");
idev = wglDXOpenDeviceNV(d3ddev);
ibb = wglDXRegisterObjectNV(idev, d3dbb, bb, GL_RENDERBUFFER, WGL_ACCESS_READ_WRITE_NV);
GetLastError();
wglDXLockObjectsNV(idev, 1, &ibb);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, bb);
glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
//wglDXUnlockObjectsNV(idev, 1, &ibb);
} else {
glBindRenderbuffer(GL_RENDERBUFFER, bb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, WIDTH, HEIGHT);
glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, bb);
glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
}
}
while (1) {
MSG msg;
while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
DispatchMessageA(&msg);
if (mode > 1) {
float col[4] = {rand()%256*(1.0f/256),0,0,1};
d3dctx->lpVtbl->ClearRenderTargetView(d3dctx, view, col);
sc->lpVtbl->Present(sc, 0, 0);
} else {
//if (mode) wglDXLockObjectsNV(idev, 1, &ibb);
glClearColor(0,rand()%256*(1.0f/256),0,1);
glClear(GL_COLOR_BUFFER_BIT);
if (mode) {
glFlush();
//wglDXUnlockObjectsNV(idev, 1, &ibb);
sc->lpVtbl->Present(sc, 0, 0);
} else {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, WIDTH, HEIGHT, 0, HEIGHT, WIDTH, 0, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glGetError();
glFlush();
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb);
}
}
{
// show fps in the window title bar. dont update it on every frame to avoid crippling the performance
static DWORD fc, last;
DWORD now = GetTickCount();
fc += 1;
if (!last) last = now;
else if (now - last > 300) {
char txt[64];
sprintf(txt, "fps: %.4f", 1000.0f * fc / (float)(now - last));
SetWindowTextA(wnd, txt);
fc = 0;
last = now;
}
}
}
}