Play-/Source/gs/GSH_OpenGL/GSH_OpenGL.h

474 lines
13 KiB
C
Raw Permalink Normal View History

#pragma once
#include <list>
#include <unordered_map>
#include "../GSHandler.h"
#include "../GsDebuggerInterface.h"
#include "../GsCachedArea.h"
#include "../GsTextureCache.h"
#include "opengl/OpenGlDef.h"
#include "opengl/Program.h"
#include "opengl/Shader.h"
#include "opengl/Resource.h"
2019-01-23 02:39:28 +00:00
#define PREF_CGSH_OPENGL_RESOLUTION_FACTOR "renderer.opengl.resfactor"
2018-04-30 21:01:23 +01:00
#define PREF_CGSH_OPENGL_FORCEBILINEARTEXTURES "renderer.opengl.forcebilineartextures"
2019-07-23 12:28:50 -04:00
#if !defined(GLES_COMPATIBILITY) && !defined(__APPLE__)
//- Dual source blending is disabled on macOS because it seems to be problematic on
// certain Intel GPUs drivers.
#define USE_DUALSOURCE_BLENDING
#endif
class CGSH_OpenGL : public CGSHandler, public CGsDebuggerInterface
{
public:
2019-12-29 17:35:52 +01:00
CGSH_OpenGL(bool = true);
2018-04-30 21:01:23 +01:00
virtual ~CGSH_OpenGL();
2018-04-30 21:01:23 +01:00
static void RegisterPreferences();
2020-01-24 09:56:38 -05:00
void LoadState(Framework::CZipArchiveReader&) override;
2018-04-30 21:01:23 +01:00
void ProcessHostToLocalTransfer() override;
void ProcessLocalToHostTransfer() override;
void ProcessLocalToLocalTransfer() override;
void ProcessClutTransfer(uint32, uint32) override;
Framework::CBitmap GetScreenshot() override;
//Debugger Interface
bool GetDepthTestingEnabled() const override;
void SetDepthTestingEnabled(bool) override;
bool GetAlphaBlendingEnabled() const override;
void SetAlphaBlendingEnabled(bool) override;
bool GetAlphaTestingEnabled() const override;
void SetAlphaTestingEnabled(bool) override;
Framework::CBitmap GetFramebuffer(uint64) override;
Framework::CBitmap GetTexture(uint64, uint32, uint64, uint64, uint32) override;
2021-08-20 11:11:45 -04:00
int GetFramebufferScale() override;
const VERTEX* GetInputVertices() const override;
2017-04-04 21:42:28 +01:00
protected:
2018-04-30 21:01:23 +01:00
void PalCache_Flush();
void LoadPreferences();
void InitializeImpl() override;
void ReleaseImpl() override;
void ResetImpl() override;
void NotifyPreferencesChangedImpl() override;
void FlipImpl() override;
2018-04-30 21:01:23 +01:00
GLuint m_presentFramebuffer = 0;
private:
typedef CGsTextureCache<Framework::OpenGl::CTexture> TextureCache;
typedef uint64 ShaderCapsInt;
struct SHADERCAPS : public convertible<ShaderCapsInt>
{
2018-04-30 21:01:23 +01:00
unsigned int texFunction : 2; //0 - Modulate, 1 - Decal, 2 - Highlight, 3 - Hightlight2
unsigned int texClampS : 3;
unsigned int texClampT : 3;
2018-04-30 21:01:23 +01:00
unsigned int texSourceMode : 2;
unsigned int texHasAlpha : 1;
unsigned int texBilinearFilter : 1;
unsigned int texUseAlphaExpansion : 1;
unsigned int texBlackIsTransparent : 1;
unsigned int hasFog : 1;
//Alpha blending caps
unsigned int hasAlphaBlend : 1;
unsigned int alphaBlendA : 2;
unsigned int alphaBlendB : 2;
unsigned int alphaBlendC : 2;
unsigned int alphaBlendD : 2;
unsigned int colorOutputWhite : 1;
//Alpha testing caps
2018-04-30 21:01:23 +01:00
unsigned int hasAlphaTest : 1;
unsigned int alphaTestMethod : 3;
unsigned int hasDestAlphaTest : 1;
unsigned int destAlphaTestRef : 1;
unsigned int alphaFailMethod : 2;
2018-04-30 21:01:23 +01:00
bool isIndexedTextureSource() const
{
return texSourceMode == TEXTURE_SOURCE_MODE_IDX4 || texSourceMode == TEXTURE_SOURCE_MODE_IDX8;
}
};
static_assert(sizeof(SHADERCAPS) == sizeof(ShaderCapsInt), "SHADERCAPS too big for ShaderCapsInt.");
struct RENDERSTATE
{
2018-04-30 21:01:23 +01:00
bool isValid;
bool isTextureStateValid;
bool isFramebufferStateValid;
//Register State
2018-04-30 21:01:23 +01:00
uint64 primReg;
uint64 frameReg;
uint64 testReg;
uint64 alphaReg;
uint64 zbufReg;
uint64 scissorReg;
uint64 tex0Reg;
uint64 tex1Reg;
uint64 texAReg;
uint64 clampReg;
uint64 fogColReg;
//Intermediate State
2018-04-30 21:01:23 +01:00
SHADERCAPS shaderCaps;
//OpenGL state
2018-04-30 21:01:23 +01:00
GLuint shaderHandle;
GLuint framebufferHandle;
GLuint texture0Handle;
GLint texture0MinFilter;
GLint texture0MagFilter;
GLint texture0WrapS;
GLint texture0WrapT;
bool texture0AlphaAsIndex;
2018-04-30 21:01:23 +01:00
GLuint texture1Handle;
GLsizei viewportWidth;
GLsizei viewportHeight;
GLint scissorX;
GLint scissorY;
GLsizei scissorWidth;
GLsizei scissorHeight;
bool blendEnabled;
bool colorMaskR;
bool colorMaskG;
bool colorMaskB;
bool colorMaskA;
bool depthMask;
bool depthTest;
};
//These need to match the layout of the shader's uniform block
struct VERTEXPARAMS
{
2018-04-30 21:01:23 +01:00
float projMatrix[16];
float texMatrix[16];
};
static_assert(sizeof(VERTEXPARAMS) == 0x80, "Size of VERTEXPARAMS must be 128 bytes.");
struct FRAGMENTPARAMS
{
2018-04-30 21:01:23 +01:00
float textureSize[2];
float texelSize[2];
float clampMin[2];
float clampMax[2];
float texA0;
float texA1;
2019-02-17 22:29:24 -05:00
uint32 alphaRef;
float alphaFix;
2018-04-30 21:01:23 +01:00
float fogColor[3];
float padding2;
};
static_assert(sizeof(FRAGMENTPARAMS) == 0x40, "Size of FRAGMENTPARAMS must be 64 bytes.");
enum
{
MAX_TEXTURE_CACHE = 256,
MAX_PALETTE_CACHE = 256,
};
enum CVTBUFFERSIZE
{
CVTBUFFERSIZE = 0x800000,
};
typedef void (CGSH_OpenGL::*TEXTUREUPDATER)(uint32, uint32, unsigned int, unsigned int, unsigned int, unsigned int);
enum
{
2018-04-30 21:01:23 +01:00
TEXTURE_SOURCE_MODE_NONE = 0,
TEXTURE_SOURCE_MODE_STD = 1,
TEXTURE_SOURCE_MODE_IDX4 = 2,
TEXTURE_SOURCE_MODE_IDX8 = 3
};
enum TEXTURE_CLAMP_MODE
{
TEXTURE_CLAMP_MODE_STD,
TEXTURE_CLAMP_MODE_CLAMP,
TEXTURE_CLAMP_MODE_REGION_CLAMP,
TEXTURE_CLAMP_MODE_REGION_REPEAT,
TEXTURE_CLAMP_MODE_REGION_REPEAT_SIMPLE
};
typedef std::unordered_map<ShaderCapsInt, Framework::OpenGl::ProgramPtr> ShaderMap;
class CPalette
{
public:
2018-04-30 21:01:23 +01:00
CPalette();
~CPalette();
2018-04-30 21:01:23 +01:00
void Invalidate(uint32);
void Free();
2018-04-30 21:01:23 +01:00
bool m_live;
2018-04-30 21:01:23 +01:00
bool m_isIDTEX4;
uint32 m_cpsm;
uint32 m_csa;
GLuint m_texture;
uint32 m_contents[256];
};
typedef std::shared_ptr<CPalette> PalettePtr;
typedef std::list<PalettePtr> PaletteList;
class CFramebuffer
{
public:
2018-04-30 21:01:23 +01:00
CFramebuffer(uint32, uint32, uint32, uint32, uint32, bool);
~CFramebuffer();
2018-04-30 21:01:23 +01:00
uint32 m_basePtr;
uint32 m_width;
uint32 m_height;
uint32 m_psm;
2018-04-30 21:01:23 +01:00
GLuint m_framebuffer = 0;
GLuint m_texture = 0;
2016-02-26 19:12:50 -05:00
2018-04-30 21:01:23 +01:00
GLuint m_resolveFramebuffer = 0;
bool m_resolveNeeded = false;
GLuint m_colorBufferMs = 0;
2018-04-30 21:01:23 +01:00
CGsCachedArea m_cachedArea;
};
typedef std::shared_ptr<CFramebuffer> FramebufferPtr;
typedef std::vector<FramebufferPtr> FramebufferList;
class CDepthbuffer
{
public:
2018-04-30 21:01:23 +01:00
CDepthbuffer(uint32, uint32, uint32, uint32, uint32, bool);
~CDepthbuffer();
uint32 m_basePtr;
uint32 m_width;
uint32 m_height;
uint32 m_psm;
GLuint m_depthBuffer;
};
typedef std::shared_ptr<CDepthbuffer> DepthbufferPtr;
typedef std::vector<DepthbufferPtr> DepthbufferList;
struct TEXTURE_INFO
{
2018-04-30 21:01:23 +01:00
GLuint textureHandle = 0;
float offsetX = 0;
float scaleRatioX = 1;
float scaleRatioY = 1;
bool alphaAsIndex = false;
};
2017-01-16 23:56:36 -05:00
struct TEXTUREFORMAT_INFO
{
GLenum internalFormat;
GLenum format;
GLenum type;
};
enum class PRIM_VERTEX_ATTRIB
{
POSITION = 1,
DEPTH,
COLOR,
TEXCOORD,
FOG,
};
struct PRIM_VERTEX
{
float x, y;
uint32 z;
uint32 color;
float s, t, q;
float f;
};
enum VERTEX_BUFFER_SIZE
{
VERTEX_BUFFER_SIZE = 0x1000,
};
typedef std::vector<PRIM_VERTEX> VertexBuffer;
2018-04-30 21:01:23 +01:00
void WriteRegisterImpl(uint8, uint64) override;
2018-04-30 21:01:23 +01:00
void InitializeRC();
void CheckExtensions();
2018-04-30 21:01:23 +01:00
void SetupTextureUpdaters();
virtual void PresentBackbuffer() = 0;
void MakeLinearZOrtho(float*, float, float, float, float);
TEXTURE_INFO PrepareTexture(const TEX0&);
TEXTURE_INFO SearchTextureFramebuffer(const TEX0&);
2018-04-30 21:01:23 +01:00
GLuint PreparePalette(const TEX0&);
2018-04-30 21:01:23 +01:00
void VertexKick(uint8, uint64);
2018-04-30 21:01:23 +01:00
Framework::OpenGl::ProgramPtr GetShaderFromCaps(const SHADERCAPS&);
Framework::OpenGl::ProgramPtr GenerateShader(const SHADERCAPS&);
Framework::OpenGl::CShader GenerateVertexShader(const SHADERCAPS&);
Framework::OpenGl::CShader GenerateFragmentShader(const SHADERCAPS&);
std::string GenerateTexCoordClampingSection(TEXTURE_CLAMP_MODE, const char*);
std::string GenerateAlphaTestSection(ALPHA_TEST_METHOD, ALPHA_TEST_FAIL_METHOD);
std::string GenerateAlphaBlendSection(ALPHABLEND_ABD, ALPHABLEND_ABD, ALPHABLEND_C, ALPHABLEND_ABD);
2018-04-30 21:01:23 +01:00
Framework::OpenGl::ProgramPtr GeneratePresentProgram();
Framework::OpenGl::CBuffer GeneratePresentVertexBuffer();
Framework::OpenGl::CVertexArray GeneratePresentVertexArray();
2018-04-30 21:01:23 +01:00
Framework::OpenGl::ProgramPtr GenerateCopyToFbProgram();
Framework::OpenGl::CBuffer GenerateCopyToFbVertexBuffer();
Framework::OpenGl::CVertexArray GenerateCopyToFbVertexArray();
2018-04-30 21:01:23 +01:00
Framework::OpenGl::CVertexArray GeneratePrimVertexArray();
Framework::OpenGl::CBuffer GenerateUniformBlockBuffer(size_t);
2018-04-30 21:01:23 +01:00
void Prim_Point();
void Prim_Line();
void Prim_Triangle();
void Prim_Sprite();
2018-04-30 21:01:23 +01:00
void FlushVertexBuffer();
void DoRenderPass();
2018-04-30 21:01:23 +01:00
void CopyToFb(int32, int32, int32, int32, int32, int32, int32, int32, int32, int32);
void DrawToDepth(unsigned int, uint64);
2018-04-30 21:01:23 +01:00
void SetRenderingContext(uint64);
void SetupTestFunctions(uint64);
void SetupDepthBuffer(uint64, uint64);
void SetupFramebuffer(uint64, uint64, uint64, uint64);
void SetupBlendingFunction(uint64);
void SetupFogColor(uint64);
2018-04-30 21:01:23 +01:00
static bool CanRegionRepeatClampModeSimplified(uint32, uint32);
void FillShaderCapsFromTexture(SHADERCAPS&, const uint64&, const uint64&, const uint64&, const uint64&);
void FillShaderCapsFromTest(SHADERCAPS&, const uint64&);
void FillShaderCapsFromAlpha(SHADERCAPS&, bool, const uint64&);
2018-04-30 21:01:23 +01:00
void SetupTexture(uint64, uint64, uint64, uint64, uint64);
static uint32 GetFramebufferBitDepth(uint32);
static TEXTUREFORMAT_INFO GetTextureFormatInfo(uint32);
2018-04-30 21:01:23 +01:00
FramebufferPtr FindFramebuffer(const FRAME&) const;
DepthbufferPtr FindDepthbuffer(const ZBUF&, const FRAME&) const;
2018-04-30 21:01:23 +01:00
void DumpTexture(unsigned int, unsigned int, uint32);
Framework::CBitmap GetFramebufferImpl(uint64);
Framework::CBitmap GetTextureImpl(uint64, uint32, uint64, uint64, uint32);
//Texture updaters
2018-04-30 21:01:23 +01:00
void TexUpdater_Invalid(uint32, uint32, unsigned int, unsigned int, unsigned int, unsigned int);
2018-04-30 21:01:23 +01:00
void TexUpdater_Psm32(uint32, uint32, unsigned int, unsigned int, unsigned int, unsigned int);
template <typename>
void TexUpdater_Psm16(uint32, uint32, unsigned int, unsigned int, unsigned int, unsigned int);
void TexUpdater_Psm8(uint32, uint32, unsigned int, unsigned int, unsigned int, unsigned int);
2021-02-28 22:18:12 +00:00
void TexUpdater_Psm4(uint32, uint32, unsigned int, unsigned int, unsigned int, unsigned int);
2021-03-10 00:24:17 +00:00
2018-04-30 21:01:23 +01:00
template <typename>
void TexUpdater_Psm48(uint32, uint32, unsigned int, unsigned int, unsigned int, unsigned int);
template <uint32, uint32>
void TexUpdater_Psm48H(uint32, uint32, unsigned int, unsigned int, unsigned int, unsigned int);
//Context variables (put this in a struct or something?)
2018-04-30 21:01:23 +01:00
float m_nPrimOfsX;
float m_nPrimOfsY;
uint32 m_nTexWidth;
uint32 m_nTexHeight;
bool m_forceBilinearTextures = false;
unsigned int m_fbScale = 1;
bool m_multisampleEnabled = false;
bool m_depthTestingEnabled = true;
bool m_alphaBlendingEnabled = true;
bool m_alphaTestingEnabled = true;
2018-04-30 21:01:23 +01:00
uint8* m_pCvtBuffer;
GLuint PalCache_Search(const TEX0&);
GLuint PalCache_Search(unsigned int, const uint32*);
void PalCache_Insert(const TEX0&, const uint32*, GLuint);
void PalCache_Invalidate(uint32);
void PopulateFramebuffer(const FramebufferPtr&);
void CommitFramebufferDirtyPages(const FramebufferPtr&, unsigned int, unsigned int);
void ResolveFramebufferMultisample(const FramebufferPtr&, uint32);
Framework::OpenGl::ProgramPtr m_presentProgram;
Framework::OpenGl::CBuffer m_presentVertexBuffer;
Framework::OpenGl::CVertexArray m_presentVertexArray;
GLint m_presentTextureUniform = -1;
GLint m_presentTexCoordScaleUniform = -1;
Framework::OpenGl::ProgramPtr m_copyToFbProgram;
Framework::OpenGl::CTexture m_copyToFbTexture;
Framework::OpenGl::CBuffer m_copyToFbVertexBuffer;
Framework::OpenGl::CVertexArray m_copyToFbVertexArray;
GLint m_copyToFbSrcPositionUniform = -1;
GLint m_copyToFbSrcSizeUniform = -1;
TextureCache m_textureCache;
PaletteList m_paletteCache;
FramebufferList m_framebuffers;
DepthbufferList m_depthbuffers;
Framework::OpenGl::CBuffer m_primBuffer;
Framework::OpenGl::CVertexArray m_primVertexArray;
VERTEX m_VtxBuffer[3];
int m_nVtxCount;
PRMODE m_PrimitiveMode;
unsigned int m_primitiveType;
bool m_drawingToDepth = false;
static const GLenum g_nativeClampModes[CGSHandler::CLAMP_MODE_MAX];
static const unsigned int g_shaderClampModes[CGSHandler::CLAMP_MODE_MAX];
static const unsigned int g_alphaTestInverse[CGSHandler::ALPHA_TEST_MAX];
TEXTUREUPDATER m_textureUpdater[CGSHandler::PSM_MAX];
enum GLSTATE_BITS : uint32
{
2018-04-30 21:01:23 +01:00
GLSTATE_VERTEX_PARAMS = 0x0001,
GLSTATE_FRAGMENT_PARAMS = 0x0002,
2018-04-30 21:01:23 +01:00
GLSTATE_PROGRAM = 0x0004,
GLSTATE_SCISSOR = 0x0008,
GLSTATE_BLEND = 0x0010,
GLSTATE_COLORMASK = 0x0020,
GLSTATE_DEPTHMASK = 0x0040,
GLSTATE_TEXTURE = 0x0080,
GLSTATE_FRAMEBUFFER = 0x0100,
GLSTATE_VIEWPORT = 0x0200,
GLSTATE_DEPTHTEST = 0x0400,
};
2018-04-30 21:01:23 +01:00
ShaderMap m_shaders;
RENDERSTATE m_renderState;
uint32 m_validGlState = 0;
VERTEXPARAMS m_vertexParams;
FRAGMENTPARAMS m_fragmentParams;
Framework::OpenGl::CBuffer m_vertexParamsBuffer;
Framework::OpenGl::CBuffer m_fragmentParamsBuffer;
VertexBuffer m_vertexBuffer;
//If GPU has framebuffer fetch extension, some things will be done
//within the shader, such alpha blending
bool m_hasFramebufferFetchExtension = false;
};