#pragma once #include "hw/pvr/ta_structs.h" #include "hw/pvr/ta_ctx.h" #include "hw/pvr/elan_struct.h" #include "rend/TexCache.h" #include "wsi/gl_context.h" #include "glcache.h" #include "rend/shader_util.h" #ifndef LIBRETRO #include "rend/imgui_driver.h" #endif #include #include #ifndef GL_TEXTURE_MAX_ANISOTROPY #define GL_TEXTURE_MAX_ANISOTROPY 0x84FE #endif #ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY #define GL_MAX_TEXTURE_MAX_ANISOTROPY 0x84FF #endif #ifndef GL_PRIMITIVE_RESTART_FIXED_INDEX #define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69 #endif #define glCheck() do { if (unlikely(config::OpenGlChecks)) { verify(glGetError()==GL_NO_ERROR); } } while(0) #define VERTEX_POS_ARRAY 0 #define VERTEX_COL_BASE_ARRAY 1 #define VERTEX_COL_OFFS_ARRAY 2 #define VERTEX_UV_ARRAY 3 // OIT only #define VERTEX_COL_BASE1_ARRAY 4 #define VERTEX_COL_OFFS1_ARRAY 5 #define VERTEX_UV1_ARRAY 6 // Naomi2 #define VERTEX_NORM_ARRAY 7 //vertex types extern u32 gcflip; extern glm::mat4 ViewportMatrix; void DrawStrips(); struct PipelineShader { GLuint program; GLint depth_scale; GLint pp_ClipTest; GLint cp_AlphaTestValue; GLint sp_FOG_COL_RAM; GLint sp_FOG_COL_VERT; GLint sp_FOG_DENSITY; GLint trilinear_alpha; GLint fog_clamp_min, fog_clamp_max; GLint ndcMat; GLint palette_index; // Naomi2 GLint mvMat; GLint normalMat; GLint projMat; GLint glossCoef[2]; GLint envMapping[2]; GLint bumpMapping; GLint constantColor[2]; GLint lightCount; GLint ambientBase[2]; GLint ambientOffset[2]; GLint ambientMaterialBase[2]; GLint ambientMaterialOffset[2]; GLint useBaseOver; GLint bumpId0; GLint bumpId1; struct { GLint color; GLint direction; GLint position; GLint parallel; GLint diffuse[2]; GLint specular[2]; GLint routing; GLint dmode; GLint smode; GLint distAttnMode; GLint attnDistA; GLint attnDistB; GLint attnAngleA; GLint attnAngleB; } lights[elan::MAX_LIGHTS]; const float *lastMvMat; const float *lastNormalMat; const float *lastProjMat; const N2LightModel *lastLightModel; // bool cp_AlphaTest; bool pp_InsideClipping; bool pp_Texture; bool pp_UseAlpha; bool pp_IgnoreTexA; u32 pp_ShadInstr; bool pp_Offset; u32 pp_FogCtrl; bool pp_Gouraud; bool pp_BumpMap; bool fog_clamping; bool trilinear; bool palette; bool naomi2; bool divPosZ; }; class GlBuffer { public: GlBuffer(GLenum type, GLenum usage = GL_STREAM_DRAW) : type(type), usage(usage), size(0) { glGenBuffers(1, &name); } ~GlBuffer() { glDeleteBuffers(1, &name); } void bind() const { glBindBuffer(type, name); } GLuint getName() const { return name; } void update(const void *data, GLsizeiptr size) { bind(); if (size > this->size) { glBufferData(type, size, data, usage); this->size = size; } else { glBufferSubData(type, 0, size, data); } } private: GLenum type; GLenum usage; GLsizeiptr size; GLuint name; }; class GlFramebuffer { public: GlFramebuffer(int width, int height, bool withDepth = false, GLuint texture = 0); GlFramebuffer(int width, int height, bool withDepth, bool withTexture); ~GlFramebuffer(); void bind(GLenum type = GL_FRAMEBUFFER) const { glBindFramebuffer(type, framebuffer); } int getWidth() const { return width; } int getHeight() const { return height; } GLuint getTexture() const { return texture; } GLuint detachTexture() { GLuint t = texture; texture = 0; return t; } GLuint getFramebuffer() const { return framebuffer; } private: void makeFramebuffer(bool withDepth); int width; int height; GLuint texture; GLuint framebuffer = 0; GLuint colorBuffer = 0; GLuint depthBuffer = 0; }; struct gl_ctx { struct { GLuint program; GLint depth_scale; GLint sp_ShaderColor; GLint ndcMat; } modvol_shader; struct { GLuint program; GLint depth_scale; GLint sp_ShaderColor; GLint ndcMat; GLint mvMat; GLint projMat; } n2ModVolShader; std::unordered_map shaders; struct { GLuint program; GLint scale; GLuint vao; GLuint geometry; GLuint osd_tex; } OSD_SHADER; struct { GLuint mainVAO; GLuint modvolVAO; std::unique_ptr geometry; std::unique_ptr modvols; std::unique_ptr idxs; } vbo; struct { u32 texAddress = ~0; GLuint pbo; u32 pboSize; bool directXfer; u32 width; u32 height; FB_W_CTRL_type fb_w_ctrl; u32 linestride; std::unique_ptr framebuffer; } rtt; struct { std::unique_ptr framebuffer; float aspectRatio; GLuint origFbo; } ofbo; struct { GLuint tex; int width; int height; } dcfb; struct { std::unique_ptr framebuffer; } fbscaling; struct { std::unique_ptr framebuffer; bool ready = false; } ofbo2; const char *gl_version; const char *glsl_version_header; int gl_major; int gl_minor; bool is_gles; GLuint single_channel_format; GLenum index_type; bool GL_OES_packed_depth_stencil_supported; bool GL_OES_depth24_supported; bool highp_float_supported; float max_anisotropy; bool mesa_nouveau; bool border_clamp_supported; bool prim_restart_supported; bool prim_restart_fixed_supported; size_t get_index_size() { return index_type == GL_UNSIGNED_INT ? sizeof(u32) : sizeof(u16); } }; extern gl_ctx gl; enum ModifierVolumeMode { Xor, Or, Inclusion, Exclusion, ModeCount }; void termGLCommon(); void findGLVersion(); void SetCull(u32 CullMode); void SetMVS_Mode(ModifierVolumeMode mv_mode, ISP_Modvol ispc); GLuint BindRTT(bool withDepthBuffer = true); void ReadRTTBuffer(); void glReadFramebuffer(const FramebufferInfo& info); GLuint init_output_framebuffer(int width, int height); void writeFramebufferToVRAM(); PipelineShader *GetProgram(bool cp_AlphaTest, bool pp_InsideClipping, bool pp_Texture, bool pp_UseAlpha, bool pp_IgnoreTexA, u32 pp_ShadInstr, bool pp_Offset, u32 pp_FogCtrl, bool pp_Gouraud, bool pp_BumpMap, bool fog_clamping, bool trilinear, bool palette, bool naomi2); GLuint gl_CompileShader(const char* shader, GLuint type); GLuint gl_CompileAndLink(const char *vertexShader, const char *fragmentShader); bool CompilePipelineShader(PipelineShader* s); extern const char* GouraudSource; extern struct ShaderUniforms_t { float PT_ALPHA; float depth_coefs[4]; float fog_den_float; float ps_FOG_COL_RAM[3]; float ps_FOG_COL_VERT[3]; float trilinear_alpha; float fog_clamp_min[4]; float fog_clamp_max[4]; glm::mat4 ndcMat; struct { bool enabled; int x; int y; int width; int height; } base_clipping; int palette_index; void Set(const PipelineShader* s) { if (s->cp_AlphaTestValue!=-1) glUniform1f(s->cp_AlphaTestValue,PT_ALPHA); if (s->depth_scale!=-1) glUniform4fv( s->depth_scale, 1, depth_coefs); if (s->sp_FOG_DENSITY!=-1) glUniform1f( s->sp_FOG_DENSITY,fog_den_float); if (s->sp_FOG_COL_RAM!=-1) glUniform3fv( s->sp_FOG_COL_RAM, 1, ps_FOG_COL_RAM); if (s->sp_FOG_COL_VERT!=-1) glUniform3fv( s->sp_FOG_COL_VERT, 1, ps_FOG_COL_VERT); if (s->fog_clamp_min != -1) glUniform4fv(s->fog_clamp_min, 1, fog_clamp_min); if (s->fog_clamp_max != -1) glUniform4fv(s->fog_clamp_max, 1, fog_clamp_max); if (s->ndcMat != -1) glUniformMatrix4fv(s->ndcMat, 1, GL_FALSE, &ndcMat[0][0]); if (s->palette_index != -1) glUniform1i(s->palette_index, palette_index); } } ShaderUniforms; class TextureCacheData final : public BaseTextureCacheData { public: TextureCacheData(TSP tsp, TCW tcw) : BaseTextureCacheData(tsp, tcw), texID(glcache.GenTexture()) { } TextureCacheData(TextureCacheData&& other) : BaseTextureCacheData(std::move(other)) { std::swap(texID, other.texID); } GLuint texID; //gl texture std::string GetId() override { return std::to_string(texID); } void UploadToGPU(int width, int height, const u8 *temp_tex_buffer, bool mipmapped, bool mipmapsIncluded = false) override; bool Delete() override; }; class GlTextureCache final : public BaseTextureCache { public: void Cleanup() { if (!texturesToDelete.empty()) { glcache.DeleteTextures((GLsizei)texturesToDelete.size(), &texturesToDelete[0]); texturesToDelete.clear(); } CollectCleanup(); } void DeleteLater(GLuint texId) { texturesToDelete.push_back(texId); } private: std::vector texturesToDelete; }; extern GlTextureCache TexCache; extern const u32 Zfunction[8]; extern const u32 SrcBlendGL[], DstBlendGL[]; struct OpenGLRenderer : Renderer { bool Init() override; void Term() override; bool Process(TA_context* ctx) override; bool Render() override; void RenderFramebuffer(const FramebufferInfo& info) override; bool RenderLastFrame() override; void DrawOSD(bool clear_screen) override; BaseTextureCacheData *GetTexture(TSP tsp, TCW tcw) override; bool Present() override { if (!frameRendered) return false; #ifndef LIBRETRO imguiDriver->setFrameRendered(); #endif frameRendered = false; return true; } protected: virtual GLenum getFogTextureSlot() const { return GL_TEXTURE1; } virtual GLenum getPaletteTextureSlot() const { return GL_TEXTURE2; } void saveCurrentFramebuffer() { #ifdef LIBRETRO gl.ofbo.origFbo = glsm_get_current_framebuffer(); #else gl.ofbo.origFbo = 0; glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *)&gl.ofbo.origFbo); #endif } void restoreCurrentFramebuffer() { glBindFramebuffer(GL_FRAMEBUFFER, gl.ofbo.origFbo); } private: bool renderFrame(int width, int height); protected: bool frameRendered = false; }; void initQuad(); void termQuad(); void drawQuad(GLuint texId, bool rotate = false, bool swapY = false); extern const char* ShaderCompatSource; extern const char *VertexCompatShader; extern const char *PixelCompatShader; class OpenGlSource : public ShaderSource { public: OpenGlSource() : ShaderSource(gl.glsl_version_header) { addConstant("TARGET_GL", gl.gl_version); addSource(ShaderCompatSource); } }; #ifdef LIBRETRO extern "C" struct retro_hw_render_callback hw_render; void termVmuLightgun(); #endif inline static void bindVertexArray(GLuint vao) { #ifndef GLES2 if (gl.gl_major >= 3) glBindVertexArray(vao); #endif } inline static void deleteVertexArray(GLuint vao) { #ifndef GLES2 if (gl.gl_major >= 3) glDeleteVertexArrays(1, &vao); #endif }