// SPDX-License-Identifier: GPL-2.0-or-later #pragma once // The GL side of showing the emulator's frames, shared by the OpenXR host and by the self test // that exercises the same path without a headset session. #include #include // Extension entry points (EGL images over hardware buffers) are only declared on request. #define EGL_EGLEXT_PROTOTYPES #define GL_GLEXT_PROTOTYPES #include #include #include // The extension header relies on the types the one above defines. #include struct AHardwareBuffer; class CoreProcess; /// An OpenGL ES 3 context that draws to nothing: everything is rendered to textures. struct GlContext { EGLDisplay display{EGL_NO_DISPLAY}; EGLConfig config{}; EGLContext context{EGL_NO_CONTEXT}; EGLSurface surface{EGL_NO_SURFACE}; bool Create(); void Destroy(); }; /// The images the emulator renders into: hardware buffers handed to it as dma-bufs, each of them /// also a GL texture here, so that a frame gets from one process to the other without a copy. class FrameBuffers { public: static constexpr uint32_t Count = 3; /// Allocates the buffers and offers them to the core. Needs a current GL context. bool Create(EGLDisplay display, uint32_t width, uint32_t height, CoreProcess& core); void Destroy(EGLDisplay display); bool IsValid(uint32_t index) const { return index < textures.size(); } GLuint Texture(uint32_t index) const { return textures[index]; } private: std::vector buffers; std::vector images; std::vector textures; }; /// Copies a frame to the framebuffer that is bound, upside up and in the right color encoding. class FrameBlitter { public: bool Create(); void Destroy(); /// `srgb_target` is for sRGB targets: they encode whatever is written to them, while the /// emulator delivers values that are display-ready already. Where the GPU can be told to /// leave that encoding out, the frame is written as it is; elsewhere it is decoded first, /// which costs a power function per pixel. void Draw(GLuint texture, uint32_t width, uint32_t height, bool swap_red_blue, bool srgb_target) const; /// Whether frames go into sRGB targets unchanged (see Draw). bool WritesUnencoded() const { return write_control; } private: GLuint program{}; GLuint vertex_array{}; GLint uniform_swap{-1}; GLint uniform_decode{-1}; bool write_control{}; };