#include "../test_harness.h" #if defined(_WIN32) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #ifndef NOMINMAX #define NOMINMAX #endif #include #include #endif #include #include #include namespace { #if defined(_WIN32) class HiddenWglContext { public: HiddenWglContext() { instance_ = GetModuleHandleW(nullptr); WNDCLASSW window_class {}; window_class.style = CS_OWNDC; window_class.lpfnWndProc = DefWindowProcW; window_class.hInstance = instance_; window_class.lpszClassName = class_name_; registered_ = RegisterClassW(&window_class) != 0 || GetLastError() == ERROR_CLASS_ALREADY_EXISTS; if (!registered_) { skip_reason_ = "RegisterClassW failed"; return; } window_ = CreateWindowExW( WS_EX_TOOLWINDOW, class_name_, L"PanoPainter GPU readback test", WS_POPUP, 0, 0, 16, 16, nullptr, nullptr, instance_, nullptr); if (window_ == nullptr) { skip_reason_ = "CreateWindowExW failed"; return; } ShowWindow(window_, SW_SHOWNA); UpdateWindow(window_); device_context_ = GetDC(window_); if (device_context_ == nullptr) { skip_reason_ = "GetDC failed"; return; } PIXELFORMATDESCRIPTOR pixel_format {}; pixel_format.nSize = sizeof(pixel_format); pixel_format.nVersion = 1; pixel_format.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pixel_format.iPixelType = PFD_TYPE_RGBA; pixel_format.cColorBits = 24; pixel_format.cAlphaBits = 8; pixel_format.cDepthBits = 24; pixel_format.iLayerType = PFD_MAIN_PLANE; const int format = ChoosePixelFormat(device_context_, &pixel_format); if (format == 0 || SetPixelFormat(device_context_, format, &pixel_format) == FALSE) { skip_reason_ = "OpenGL pixel format setup failed"; return; } render_context_ = wglCreateContext(device_context_); if (render_context_ == nullptr) { skip_reason_ = "wglCreateContext failed"; return; } if (wglMakeCurrent(device_context_, render_context_) == FALSE) { skip_reason_ = "wglMakeCurrent failed"; return; } ready_ = true; } HiddenWglContext(const HiddenWglContext&) = delete; HiddenWglContext& operator=(const HiddenWglContext&) = delete; ~HiddenWglContext() { if (render_context_ != nullptr) { wglMakeCurrent(nullptr, nullptr); wglDeleteContext(render_context_); } if (window_ != nullptr && device_context_ != nullptr) { ReleaseDC(window_, device_context_); } if (window_ != nullptr) { DestroyWindow(window_); } if (registered_) { UnregisterClassW(class_name_, instance_); } } [[nodiscard]] bool ready() const noexcept { return ready_; } [[nodiscard]] const char* skip_reason() const noexcept { return skip_reason_; } private: static constexpr const wchar_t* class_name_ = L"PanoPainterGpuReadbackTestWindow"; HINSTANCE instance_ = nullptr; HWND window_ = nullptr; HDC device_context_ = nullptr; HGLRC render_context_ = nullptr; const char* skip_reason_ = "OpenGL context unavailable"; bool registered_ = false; bool ready_ = false; }; #endif void opengl_clear_readback_matches_fixture(pp::tests::Harness& h) { #if defined(_WIN32) HiddenWglContext context; if (!context.ready()) { std::cout << "[skip] desktop GPU OpenGL readback unavailable: " << context.skip_reason() << "\n"; return; } glViewport(0, 0, 1, 1); glDrawBuffer(GL_BACK); glReadBuffer(GL_BACK); glClearColor(1.0F, 0.0F, 0.0F, 1.0F); glClear(GL_COLOR_BUFFER_BIT); glFinish(); std::array pixel {}; glReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel.data()); constexpr std::array expected { 255, 0, 0, 255, }; if (pixel != expected) { std::cout << "readback rgba: " << static_cast(pixel[0]) << ", " << static_cast(pixel[1]) << ", " << static_cast(pixel[2]) << ", " << static_cast(pixel[3]) << "\n"; } PP_EXPECT(h, pixel == expected); #else std::cout << "[skip] desktop GPU OpenGL readback unavailable: no platform context helper\n"; #endif } } int main() { pp::tests::Harness harness; harness.run("opengl_clear_readback_matches_fixture", opengl_clear_readback_matches_fixture); return harness.finish(); }