mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-11-03 21:46:32 +00:00
168 lines
5.7 KiB
C
168 lines
5.7 KiB
C
/* Independent Direct3D 9 workload for a 32-bit program: renders sixty frames into a window with the fixed-function pipeline and presents each.
|
|
* Frame number n clears to a colour that depends on n and draws one red triangle with pre-transformed vertices. The first and the last back
|
|
* buffer are copied with the GPU into system memory and written as RGBA to C:\window_first.raw and C:\window_last.raw; C:\window.txt says OK
|
|
* once every frame was presented. The program then keeps the last frame on screen for a few seconds so that a compositor capture can be
|
|
* compared with the read-back pixels. */
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define COBJMACROS
|
|
#include <windows.h>
|
|
#include <d3d9.h>
|
|
|
|
#define SIZE 256
|
|
#define FRAMES 60
|
|
|
|
struct vertex { float x, y, z, w; DWORD color; };
|
|
#define FVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
|
|
|
|
static void write_file(const char *path, const void *data, DWORD size)
|
|
{
|
|
HANDLE file = CreateFileA(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
|
DWORD written;
|
|
WriteFile(file, data, size, &written, NULL);
|
|
CloseHandle(file);
|
|
}
|
|
|
|
static void say(const char *text)
|
|
{
|
|
DWORD length = 0;
|
|
while (text[length])
|
|
++length;
|
|
write_file("C:\\window.txt", text, length);
|
|
}
|
|
|
|
static void fail(const char *step, HRESULT result)
|
|
{
|
|
char text[64];
|
|
int length = 0;
|
|
const char *prefix = "FAIL ";
|
|
while (*prefix)
|
|
text[length++] = *prefix++;
|
|
while (*step && length < 40)
|
|
text[length++] = *step++;
|
|
text[length++] = ' ';
|
|
for (int shift = 28; shift >= 0; shift -= 4)
|
|
text[length++] = "0123456789abcdef"[((unsigned)result >> shift) & 15];
|
|
text[length] = 0;
|
|
say(text);
|
|
ExitProcess(1);
|
|
}
|
|
|
|
static LRESULT CALLBACK procedure(HWND window, UINT message, WPARAM wparam, LPARAM lparam)
|
|
{
|
|
if (message == WM_DESTROY) {
|
|
PostQuitMessage(0);
|
|
return 0;
|
|
}
|
|
return DefWindowProcA(window, message, wparam, lparam);
|
|
}
|
|
|
|
static void pump(void)
|
|
{
|
|
MSG message;
|
|
while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) {
|
|
TranslateMessage(&message);
|
|
DispatchMessageA(&message);
|
|
}
|
|
}
|
|
|
|
typedef IDirect3D9 *(WINAPI *create_function)(UINT);
|
|
|
|
static void read_back(IDirect3DDevice9 *device, IDirect3DSurface9 *staging, const char *path)
|
|
{
|
|
IDirect3DSurface9 *back = NULL;
|
|
HRESULT result = IDirect3DDevice9_GetBackBuffer(device, 0, 0, D3DBACKBUFFER_TYPE_MONO, &back);
|
|
if (result != D3D_OK)
|
|
fail("GetBackBuffer", result);
|
|
result = IDirect3DDevice9_GetRenderTargetData(device, back, staging);
|
|
if (result != D3D_OK)
|
|
fail("GetRenderTargetData", result);
|
|
D3DLOCKED_RECT locked;
|
|
result = IDirect3DSurface9_LockRect(staging, &locked, NULL, D3DLOCK_READONLY);
|
|
if (result != D3D_OK)
|
|
fail("LockRect", result);
|
|
static unsigned char pixels[SIZE * SIZE * 4];
|
|
for (int y = 0; y < SIZE; ++y) {
|
|
const unsigned char *row = (const unsigned char *)locked.pBits + y * locked.Pitch;
|
|
for (int x = 0; x < SIZE; ++x) {
|
|
pixels[(y * SIZE + x) * 4 + 0] = row[x * 4 + 2];
|
|
pixels[(y * SIZE + x) * 4 + 1] = row[x * 4 + 1];
|
|
pixels[(y * SIZE + x) * 4 + 2] = row[x * 4 + 0];
|
|
pixels[(y * SIZE + x) * 4 + 3] = 255;
|
|
}
|
|
}
|
|
IDirect3DSurface9_UnlockRect(staging);
|
|
IDirect3DSurface9_Release(back);
|
|
write_file(path, pixels, sizeof pixels);
|
|
}
|
|
|
|
int raven_entry(void)
|
|
{
|
|
WNDCLASSA window_class = {0};
|
|
window_class.lpfnWndProc = procedure;
|
|
window_class.hInstance = GetModuleHandleA(NULL);
|
|
window_class.lpszClassName = "raven_d3d9_window";
|
|
RegisterClassA(&window_class);
|
|
HWND window = CreateWindowExA(0, "raven_d3d9_window", "d3d9", WS_POPUP | WS_VISIBLE, 0, 0, SIZE, SIZE, NULL, NULL, window_class.hInstance, NULL);
|
|
if (!window)
|
|
fail("window", 0);
|
|
HMODULE library = LoadLibraryA("d3d9.dll");
|
|
if (!library)
|
|
fail("d3d9.dll", GetLastError());
|
|
create_function create = (create_function)GetProcAddress(library, "Direct3DCreate9");
|
|
if (!create)
|
|
fail("Direct3DCreate9", 0);
|
|
IDirect3D9 *direct3d = create(D3D_SDK_VERSION);
|
|
if (!direct3d)
|
|
fail("create", 0);
|
|
D3DPRESENT_PARAMETERS parameters = {0};
|
|
parameters.Windowed = TRUE;
|
|
parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
parameters.BackBufferFormat = D3DFMT_X8R8G8B8;
|
|
parameters.BackBufferWidth = SIZE;
|
|
parameters.BackBufferHeight = SIZE;
|
|
parameters.BackBufferCount = 1;
|
|
parameters.hDeviceWindow = window;
|
|
parameters.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
IDirect3DDevice9 *device = NULL;
|
|
HRESULT result = IDirect3D9_CreateDevice(direct3d, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window, D3DCREATE_SOFTWARE_VERTEXPROCESSING, ¶meters, &device);
|
|
if (result != D3D_OK)
|
|
fail("CreateDevice", result);
|
|
IDirect3DSurface9 *staging = NULL;
|
|
result = IDirect3DDevice9_CreateOffscreenPlainSurface(device, SIZE, SIZE, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &staging, NULL);
|
|
if (result != D3D_OK)
|
|
fail("CreateOffscreenPlainSurface", result);
|
|
struct vertex triangle[3] = {
|
|
{128.0f, 24.0f, 0.5f, 1.0f, 0xffff0000u},
|
|
{232.0f, 232.0f, 0.5f, 1.0f, 0xffff0000u},
|
|
{24.0f, 232.0f, 0.5f, 1.0f, 0xffff0000u},
|
|
};
|
|
for (int frame = 0; frame < FRAMES; ++frame) {
|
|
const DWORD clear = 0xff000000u | (DWORD)(frame * 4) << 8 | 0x40u;
|
|
result = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET, clear, 1.0f, 0);
|
|
if (result != D3D_OK)
|
|
fail("Clear", result);
|
|
result = IDirect3DDevice9_BeginScene(device);
|
|
if (result != D3D_OK)
|
|
fail("BeginScene", result);
|
|
IDirect3DDevice9_SetFVF(device, FVF);
|
|
result = IDirect3DDevice9_DrawPrimitiveUP(device, D3DPT_TRIANGLELIST, 1, triangle, sizeof(struct vertex));
|
|
if (result != D3D_OK)
|
|
fail("DrawPrimitiveUP", result);
|
|
IDirect3DDevice9_EndScene(device);
|
|
if (frame == 0)
|
|
read_back(device, staging, "C:\\window_first.raw");
|
|
if (frame == FRAMES - 1)
|
|
read_back(device, staging, "C:\\window_last.raw");
|
|
result = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);
|
|
if (result != D3D_OK)
|
|
fail("Present", result);
|
|
pump();
|
|
}
|
|
say("OK");
|
|
for (int tick = 0; tick < 100; ++tick) {
|
|
pump();
|
|
Sleep(100);
|
|
}
|
|
return 0;
|
|
}
|