Supermodel/Src/Graphics/New3D/New3D.h
Ian Curtis edb11dc223 Performance improvements
The old texture code was being bottle necked by the texture reads. We mirrored the real3d texture memory directly, including the mipmaps in a single large texture. I *think* most h/w has some sort of texture cache for a 2x2 or 4x4 block of pixels for a texture. What we were doing was reading the base texture, then reading the mipmap data from a totally separate part of the same texture which I can only assume flushed this cache. What I did was to create mipmap chains for the texture sheet, then copy the mipmap data there. Doing this basically doubles performance.
2024-06-13 13:36:30 +01:00

313 lines
9.1 KiB
C++

/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski, Nik Henson
**
** This file is part of Supermodel.
**
** Supermodel 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, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel 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 for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* New3D.h
*
* Header file defining the CNew3D class: OpenGL Real3D graphics engine.
*/
#ifndef INCLUDED_NEW3D_H
#define INCLUDED_NEW3D_H
#include <GL/glew.h>
#include "Types.h"
#include "Graphics/IRender3D.h"
#include "Model.h"
#include "Mat4.h"
#include "R3DShader.h"
#include "VBO.h"
#include "R3DData.h"
#include "Plane.h"
#include "Vec.h"
#include "R3DScrollFog.h"
#include "PolyHeader.h"
#include "R3DFrameBuffers.h"
#include <mutex>
#include "TextureBank.h"
namespace New3D {
class CNew3D : public IRender3D
{
public:
/*
* RenderFrame(void):
*
* Renders the complete scene database. Must be called between BeginFrame() and
* EndFrame(). This function traverses the scene database and builds up display
* lists.
*/
void RenderFrame(void);
/*
* BeginFrame(void):
*
* Prepare to render a new frame. Must be called once per frame prior to
* drawing anything.
*/
void BeginFrame(void);
/*
* EndFrame(void):
*
* Signals the end of rendering for this frame. Must be called last during
* the frame.
*/
void EndFrame(void);
/*
* UploadTextures(x, y, width, height):
*
* Signals that a portion of texture RAM has been updated.
*
* Parameters:
* x X position within texture RAM.
* y Y position within texture RAM.
* width Width of texture data in texels.
* height Height.
*/
void UploadTextures(unsigned level, unsigned x, unsigned y, unsigned width, unsigned height);
/*
* AttachMemory(cullingRAMLoPtr, cullingRAMHiPtr, polyRAMPtr, vromPtr,
* textureRAMPtr):
*
* Attaches RAM and ROM areas. This must be done prior to any rendering
* otherwise the program may crash with an access violation.
*
* Parameters:
* cullingRAMLoPtr Pointer to low culling RAM (4 MB).
* cullingRAMHiPtr Pointer to high culling RAM (1 MB).
* polyRAMPtr Pointer to polygon RAM (4 MB).
* vromPtr Pointer to video ROM (64 MB).
* textureRAMPtr Pointer to texture RAM (8 MB).
*/
void AttachMemory(const UINT32 *cullingRAMLoPtr,
const UINT32 *cullingRAMHiPtr, const UINT32 *polyRAMPtr,
const UINT32 *vromPtr, const UINT16 *textureRAMPtr);
/*
* SetStepping(stepping):
*
* Sets the Model 3 hardware stepping, which also determines the Real3D
* functionality. The default is Step 1.0. This should be called prior to
* any other emulation functions and after Init().
*
* Parameters:
* stepping 0x10 for Step 1.0, 0x15 for Step 1.5, 0x20 for Step 2.0, or
* 0x21 for Step 2.1. Anything else defaults to 1.0.
*/
void SetStepping(int stepping);
/*
* Init(xOffset, yOffset, xRes, yRes, totalXRes, totalYRes):
*
* One-time initialization of the context. Must be called before any other
* members (meaning it should be called even before being attached to any
* other objects that want to use it).
*
* External shader files are loaded according to configuration settings.
*
* Parameters:
* xOffset X offset of the viewable area within OpenGL display
* surface, in pixels.
* yOffset Y offset.
* xRes Horizontal resolution of the viewable area.
* yRes Vertical resolution.
* totalXRes Horizontal resolution of the complete display area.
* totalYRes Vertical resolution.
*
* Returns:
* OKAY is successful, otherwise FAILED if a non-recoverable error
* occurred. Any allocated memory will not be freed until the
* destructor is called. Prints own error messages.
*/
bool Init(unsigned xOffset, unsigned yOffset, unsigned xRes, unsigned yRes, unsigned totalXRes, unsigned totalYRes, unsigned aaTarget);
/*
* SetSunClamp(bool enable);
*
* Sets or unsets the clamped light model
*
* Parameters:
* enable Set clamp mode
*/
void SetSunClamp(bool enable);
/*
* SetSignedShade(bool enable);
*
* Sets the sign-ness of fixed shading value
*
* Parameters:
* enable Fixed shading is expressed as signed value
*/
void SetSignedShade(bool enable);
/*
* GetLosValue(int layer);
*
* Gets the line of sight value for the priority layer
*
* Parameters:
* layer Priority layer to read from
*/
float GetLosValue(int layer);
/*
* CRender3D(config):
* ~CRender3D(void):
*
* Constructor and destructor.
*
* Parameters:
* config Run-time configuration.
*/
CNew3D(const Util::Config::Node &config, const std::string& gameName);
~CNew3D(void);
private:
/*
* Private Members
*/
// Real3D address translation
const UINT32 *TranslateCullingAddress(UINT32 addr);
const UINT32 *TranslateModelAddress(UINT32 addr);
// Matrix stack
void MultMatrix(UINT32 matrixOffset, Mat4& mat);
void InitMatrixStack(UINT32 matrixBaseAddr, Mat4& mat);
void ResetMatrix(Mat4& mat);
// Scene database traversal
bool DrawModel(UINT32 modelAddr);
void DescendCullingNode(UINT32 addr);
void DescendPointerList(UINT32 addr);
void DescendNodePtr(UINT32 nodeAddr);
void RenderViewport(UINT32 addr);
// building the scene
int GetTexFormat(int originalFormat, bool contour);
void SetMeshValues(SortingMesh *currentMesh, PolyHeader &ph);
void CacheModel(Model *m, const UINT32 *data);
void CopyVertexData(const R3DPoly& r3dPoly, std::vector<FVertex>& vertexArray);
void GetCoordinates(int width, int height, UINT16 uIn, UINT16 vIn, float uvScale, float& uOut, float& vOut);
bool RenderScene(int priority, bool renderOverlay, Layer layer); // returns if has overlay plane
bool IsDynamicModel(UINT32 *data); // check if the model has a colour palette
bool IsVROMModel(UINT32 modelAddr);
void DrawScrollFog();
void DrawAmbientFog();
bool SkipLayer(int layer);
void SetRenderStates();
void DisableRenderStates();
void TranslateLosPosition(int inX, int inY, int& outX, int& outY);
bool ProcessLos(int priority);
void CalcViewport(Viewport* vp);
void TranslateTexture(unsigned& x, unsigned& y, int width, int height, int& page);
/*
* Data
*/
// Misc
std::string m_gameName;
int m_numPolyVerts;
GLenum m_primType;
// GPU configuration
bool m_sunClamp;
bool m_shadeIsSigned;
// Stepping
int m_step;
int m_offset; // offset to subtract for words 3 and higher of culling nodes
float m_vertexFactor; // fixed-point conversion factor for vertices
// Memory (passed from outside)
const UINT32 *m_cullingRAMLo; // 4 MB
const UINT32 *m_cullingRAMHi; // 1 MB
const UINT32 *m_polyRAM; // 4 MB
const UINT32 *m_vrom; // 64 MB
const UINT16 *m_textureRAM; // 8 MB
// Resolution and scaling factors (to support resolutions higher than 496x384) and offsets
float m_xRatio, m_yRatio;
unsigned m_xOffs, m_yOffs;
unsigned m_xRes, m_yRes; // resolution of Model 3's 496x384 display area within the window
unsigned m_totalXRes, m_totalYRes; // total OpenGL window resolution
// Real3D Base Matrix Pointer
const float *m_matrixBasePtr;
UINT32 m_colorTableAddr = 0x400; // address of color table in polygon RAM
LODBlendTable* m_LODBlendTable;
NodeAttributes m_nodeAttribs;
Mat4 m_modelMat; // current modelview matrix
struct LOS
{
float value[4] = { 0,0,0,0 }; // line of sight value for each priority layer
} m_los[2];
LOS* m_losFront = &m_los[0]; // we need to double buffer this because 3d works in separate thread
LOS* m_losBack = &m_los[1];
std::mutex m_losMutex;
Vertex m_prev[4]; // these are class variables because sega bass fishing starts meshes with shared vertices from the previous one
UINT16 m_prevTexCoords[4][2]; // basically relying on undefined behavour
std::vector<Node> m_nodes; // this represents the entire render frame
std::vector<FVertex> m_polyBufferRam; // dynamic polys
std::vector<FVertex> m_polyBufferRom; // rom polys
std::unordered_map<UINT32, std::shared_ptr<std::vector<Mesh>>> m_romMap; // a hash table for all the ROM models. The meshes don't have model matrices or tex offsets yet
TextureBank m_textureBank[2];
GLuint m_vao;
VBO m_vbo; // large VBO to hold our poly data, start of VBO is ROM data, ram polys follow
R3DShader m_r3dShader;
R3DScrollFog m_r3dScrollFog;
R3DFrameBuffers m_r3dFrameBuffers;
GLuint m_aaTarget; // optional, maybe zero
int m_currentPriority;
struct
{
float bnlu;
float bnlv;
float bntu;
float bntw;
float bnru;
float bnrv;
float bnbu;
float bnbw;
float correction;
} m_planes;
};
} // New3D
#endif // INCLUDED_NEW3D_H