mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-11 16:49:12 +01:00
a357c77257
PS and VS making. Untested and won't work for now. Add in program shader cache files. Readd NativeVertexFormat stuffs. Add in PS and VS cache things. SetShaders in places. Fixed EFB cache index computations in OpenGL renderer. The previous computation was very likely to go out of array bounds, which could result in crashes on EFB access. Also, the cache size was rounded down instead of up. This is a problem since EFB_HEIGHT (528) is not a multiple of EFB_CACHE_RECT_SIZE (64).
299 lines
9.0 KiB
C++
299 lines
9.0 KiB
C++
// Copyright (C) 2003 Dolphin Project.
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, version 2.0.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
#include "GLUtil.h"
|
|
#include "x64Emitter.h"
|
|
#include "ABI.h"
|
|
#include "MemoryUtil.h"
|
|
#include "ProgramShaderCache.h"
|
|
#include "VertexShaderGen.h"
|
|
|
|
#include "CPMemory.h"
|
|
#include "NativeVertexFormat.h"
|
|
#include "VertexManager.h"
|
|
|
|
#define COMPILED_CODE_SIZE 4096
|
|
|
|
// TODO: this guy is never initialized
|
|
u32 s_prevcomponents; // previous state set
|
|
/*
|
|
#ifdef _WIN32
|
|
#ifdef _M_IX86
|
|
#define USE_JIT
|
|
#endif
|
|
#endif
|
|
*/
|
|
// Note the use of CallCdeclFunction3I etc.
|
|
// This is a horrible hack that is necessary because in 64-bit mode, Opengl32.dll is based way, way above the 32-bit
|
|
// address space that is within reach of a CALL, and just doing &fn gives us these high uncallable addresses. So we
|
|
// want to grab the function pointers from the import table instead.
|
|
|
|
// This problem does not apply to glew functions, only core opengl32 functions.
|
|
|
|
// Here's some global state. We only use this to keep track of what we've sent to the OpenGL state
|
|
// machine.
|
|
|
|
#ifdef USE_JIT
|
|
DECLARE_IMPORT(glNormalPointer);
|
|
DECLARE_IMPORT(glVertexPointer);
|
|
DECLARE_IMPORT(glColorPointer);
|
|
DECLARE_IMPORT(glTexCoordPointer);
|
|
#endif
|
|
|
|
class GLVertexFormat : public NativeVertexFormat
|
|
{
|
|
u8 *m_compiledCode;
|
|
PortableVertexDeclaration vtx_decl;
|
|
|
|
public:
|
|
GLVertexFormat();
|
|
~GLVertexFormat();
|
|
|
|
virtual void Initialize(const PortableVertexDeclaration &_vtx_decl);
|
|
virtual void SetupVertexPointers();
|
|
virtual void EnableComponents(u32 components);
|
|
};
|
|
|
|
namespace OGL
|
|
{
|
|
|
|
NativeVertexFormat* VertexManager::CreateNativeVertexFormat()
|
|
{
|
|
return new GLVertexFormat();
|
|
}
|
|
|
|
}
|
|
|
|
GLVertexFormat::GLVertexFormat()
|
|
{
|
|
#ifdef USE_JIT
|
|
m_compiledCode = (u8 *)AllocateExecutableMemory(COMPILED_CODE_SIZE, false);
|
|
if (m_compiledCode)
|
|
memset(m_compiledCode, 0, COMPILED_CODE_SIZE);
|
|
#endif
|
|
}
|
|
|
|
GLVertexFormat::~GLVertexFormat()
|
|
{
|
|
#ifdef USE_JIT
|
|
FreeMemoryPages(m_compiledCode, COMPILED_CODE_SIZE);
|
|
m_compiledCode = 0;
|
|
#endif
|
|
}
|
|
|
|
inline GLuint VarToGL(VarType t)
|
|
{
|
|
static const GLuint lookup[5] = {
|
|
GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FLOAT
|
|
};
|
|
return lookup[t];
|
|
}
|
|
|
|
void GLVertexFormat::Initialize(const PortableVertexDeclaration &_vtx_decl)
|
|
{
|
|
s_prevcomponents = 0;
|
|
|
|
vertex_stride = _vtx_decl.stride;
|
|
using namespace Gen;
|
|
|
|
// We will not allow vertex components causing uneven strides.
|
|
if (_vtx_decl.stride & 3)
|
|
PanicAlert("Uneven vertex stride: %i", _vtx_decl.stride);
|
|
|
|
#ifdef USE_JIT
|
|
Gen::XEmitter emit(m_compiledCode);
|
|
// Alright, we have our vertex declaration. Compile some crazy code to set it quickly using GL.
|
|
emit.ABI_EmitPrologue(6);
|
|
|
|
emit.CallCdeclFunction4_I(glVertexPointer, 3, GL_FLOAT, _vtx_decl.stride, 0);
|
|
|
|
if (_vtx_decl.num_normals >= 1)
|
|
{
|
|
emit.CallCdeclFunction3_I(glNormalPointer, VarToGL(_vtx_decl.normal_gl_type), _vtx_decl.stride, _vtx_decl.normal_offset[0]);
|
|
if (_vtx_decl.num_normals == 3) {
|
|
emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_NORM1_ATTRIB, _vtx_decl.normal_gl_size, VarToGL(_vtx_decl.normal_gl_type), GL_TRUE, _vtx_decl.stride, _vtx_decl.normal_offset[1]);
|
|
emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_NORM2_ATTRIB, _vtx_decl.normal_gl_size, VarToGL(_vtx_decl.normal_gl_type), GL_TRUE, _vtx_decl.stride, _vtx_decl.normal_offset[2]);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
if (_vtx_decl.color_offset[i] != -1)
|
|
{
|
|
if (i == 0)
|
|
emit.CallCdeclFunction4_I(glColorPointer, 4, GL_UNSIGNED_BYTE, _vtx_decl.stride, _vtx_decl.color_offset[i]);
|
|
else
|
|
emit.CallCdeclFunction4((void *)glSecondaryColorPointer, 4, GL_UNSIGNED_BYTE, _vtx_decl.stride, _vtx_decl.color_offset[i]);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
{
|
|
if (_vtx_decl.texcoord_offset[i] != -1)
|
|
{
|
|
int id = GL_TEXTURE0 + i;
|
|
#ifdef _M_X64
|
|
#ifdef _MSC_VER
|
|
emit.MOV(32, R(RCX), Imm32(id));
|
|
#else
|
|
emit.MOV(32, R(RDI), Imm32(id));
|
|
#endif
|
|
#else
|
|
emit.ABI_AlignStack(1 * 4);
|
|
emit.PUSH(32, Imm32(id));
|
|
#endif
|
|
emit.CALL((void *)glClientActiveTexture);
|
|
#ifndef _M_X64
|
|
#ifdef _WIN32
|
|
// don't inc stack on windows, stdcall
|
|
#else
|
|
emit.ABI_RestoreStack(1 * 4);
|
|
#endif
|
|
#endif
|
|
emit.CallCdeclFunction4_I(
|
|
glTexCoordPointer, _vtx_decl.texcoord_size[i], VarToGL(_vtx_decl.texcoord_gl_type[i]),
|
|
_vtx_decl.stride, _vtx_decl.texcoord_offset[i]);
|
|
}
|
|
}
|
|
|
|
if (_vtx_decl.posmtx_offset != -1)
|
|
emit.CallCdeclFunction6((void *)glVertexAttribPointer, SHADER_POSMTX_ATTRIB, 4, GL_UNSIGNED_BYTE, GL_FALSE, _vtx_decl.stride, _vtx_decl.posmtx_offset);
|
|
|
|
emit.ABI_EmitEpilogue(6);
|
|
|
|
if (emit.GetCodePtr() - (u8*)m_compiledCode > COMPILED_CODE_SIZE)
|
|
Crash();
|
|
|
|
#endif
|
|
this->vtx_decl = _vtx_decl;
|
|
}
|
|
|
|
void GLVertexFormat::SetupVertexPointers() {
|
|
// Cast a pointer to compiled code to a pointer to a function taking no parameters, through a (void *) cast first to
|
|
// get around type checking errors, and call it.
|
|
#ifdef USE_JIT
|
|
((void (*)())(void*)m_compiledCode)();
|
|
#else
|
|
glVertexPointer(3, GL_FLOAT, vtx_decl.stride, VertexManager::s_pBaseBufferPointer);
|
|
if (vtx_decl.num_normals >= 1) {
|
|
glNormalPointer(VarToGL(vtx_decl.normal_gl_type), vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[0]));
|
|
if (vtx_decl.num_normals == 3) {
|
|
GLint varLocation1 = SHADER_NORM1_ATTRIB, varLocation2 = SHADER_NORM2_ATTRIB;
|
|
if(g_ActiveConfig.bUseGLSL){
|
|
varLocation1 = OGL::ProgramShaderCache::GetAttr(0);
|
|
varLocation2 = OGL::ProgramShaderCache::GetAttr(1);
|
|
}
|
|
if(varLocation1 > 0)
|
|
glVertexAttribPointer(varLocation1, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[1]));
|
|
if(varLocation2 > 0)
|
|
glVertexAttribPointer(varLocation2, vtx_decl.normal_gl_size, VarToGL(vtx_decl.normal_gl_type), GL_TRUE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.normal_offset[2]));
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
if (vtx_decl.color_offset[i] != -1) {
|
|
if (i == 0)
|
|
glColorPointer(4, GL_UNSIGNED_BYTE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.color_offset[i]));
|
|
else {
|
|
glSecondaryColorPointer(4, GL_UNSIGNED_BYTE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.color_offset[i]));
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 8; i++) {
|
|
if (vtx_decl.texcoord_offset[i] != -1) {
|
|
int id = GL_TEXTURE0 + i;
|
|
glClientActiveTexture(id);
|
|
glTexCoordPointer(vtx_decl.texcoord_size[i], VarToGL(vtx_decl.texcoord_gl_type[i]),
|
|
vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.texcoord_offset[i]));
|
|
}
|
|
}
|
|
|
|
if (vtx_decl.posmtx_offset != -1) {
|
|
GLint varLocation = SHADER_POSMTX_ATTRIB;
|
|
if(g_ActiveConfig.bUseGLSL)
|
|
varLocation = OGL::ProgramShaderCache::GetAttr(2);
|
|
if(varLocation > 0)
|
|
glVertexAttribPointer(varLocation, 4, GL_UNSIGNED_BYTE, GL_FALSE, vtx_decl.stride, (void *)(VertexManager::s_pBaseBufferPointer + vtx_decl.posmtx_offset));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void GLVertexFormat::EnableComponents(u32 components)
|
|
{
|
|
if (s_prevcomponents != components)
|
|
{
|
|
VertexManager::Flush();
|
|
|
|
// matrices
|
|
if ((components & VB_HAS_POSMTXIDX) != (s_prevcomponents & VB_HAS_POSMTXIDX))
|
|
{
|
|
if (components & VB_HAS_POSMTXIDX)
|
|
glEnableVertexAttribArray(SHADER_POSMTX_ATTRIB);
|
|
else
|
|
glDisableVertexAttribArray(SHADER_POSMTX_ATTRIB);
|
|
}
|
|
|
|
// normals
|
|
if ((components & VB_HAS_NRM0) != (s_prevcomponents & VB_HAS_NRM0))
|
|
{
|
|
if (components & VB_HAS_NRM0)
|
|
glEnableClientState(GL_NORMAL_ARRAY);
|
|
else
|
|
glDisableClientState(GL_NORMAL_ARRAY);
|
|
}
|
|
if ((components & VB_HAS_NRM1) != (s_prevcomponents & VB_HAS_NRM1))
|
|
{
|
|
if (components & VB_HAS_NRM1) {
|
|
glEnableVertexAttribArray(SHADER_NORM1_ATTRIB);
|
|
glEnableVertexAttribArray(SHADER_NORM2_ATTRIB);
|
|
}
|
|
else {
|
|
glDisableVertexAttribArray(SHADER_NORM1_ATTRIB);
|
|
glDisableVertexAttribArray(SHADER_NORM2_ATTRIB);
|
|
}
|
|
}
|
|
|
|
// color
|
|
for (int i = 0; i < 2; ++i)
|
|
{
|
|
if ((components & (VB_HAS_COL0 << i)) != (s_prevcomponents & (VB_HAS_COL0 << i)))
|
|
{
|
|
if (components & (VB_HAS_COL0 << i))
|
|
glEnableClientState(i ? GL_SECONDARY_COLOR_ARRAY : GL_COLOR_ARRAY);
|
|
else
|
|
glDisableClientState(i ? GL_SECONDARY_COLOR_ARRAY : GL_COLOR_ARRAY);
|
|
}
|
|
}
|
|
|
|
// tex
|
|
for (int i = 0; i < 8; ++i)
|
|
{
|
|
if ((components & (VB_HAS_UV0 << i)) != (s_prevcomponents & (VB_HAS_UV0 << i)))
|
|
{
|
|
glClientActiveTexture(GL_TEXTURE0 + i);
|
|
if (components & (VB_HAS_UV0 << i))
|
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
else
|
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
}
|
|
}
|
|
|
|
s_prevcomponents = components;
|
|
}
|
|
}
|