mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 23:25:40 +12:00
Merge pull request #141 from GPUCode/stencil-logicop-clear
Depth buffer fixes
This commit is contained in:
commit
6a6b3cf892
8 changed files with 295 additions and 86 deletions
|
@ -53,9 +53,13 @@ namespace PICA {
|
|||
// Framebuffer registers
|
||||
ColourOperation = 0x100,
|
||||
BlendFunc = 0x101,
|
||||
LogicOp = 0x102,
|
||||
BlendColour = 0x103,
|
||||
AlphaTestConfig = 0x104,
|
||||
StencilTest = 0x105,
|
||||
StencilOp = 0x106,
|
||||
DepthAndColorMask = 0x107,
|
||||
DepthBufferWrite = 0x115,
|
||||
DepthBufferFormat = 0x116,
|
||||
ColourBufferFormat = 0x117,
|
||||
DepthBufferLoc = 0x11C,
|
||||
|
@ -292,4 +296,4 @@ namespace PICA {
|
|||
GeometryPrimitive = 3,
|
||||
};
|
||||
|
||||
} // namespace PICA
|
||||
} // namespace PICA
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <type_traits>
|
||||
|
||||
#include "helpers.hpp"
|
||||
#include "opengl.hpp"
|
||||
|
||||
// GL state manager object for use in the OpenGL GPU renderer and potentially other things in the future (such as a potential ImGui GUI)
|
||||
|
@ -18,28 +19,39 @@
|
|||
// backend-agnostic as possible
|
||||
|
||||
struct GLStateManager {
|
||||
// We only support 6 clipping planes in our state manager because that's the minimum for GL_MAX_CLIP_PLANES
|
||||
// And nobody needs more than 6 clip planes anyways
|
||||
static constexpr GLint clipPlaneCount = 6;
|
||||
|
||||
bool blendEnabled;
|
||||
bool logicOpEnabled;
|
||||
bool depthEnabled;
|
||||
bool scissorEnabled;
|
||||
bool stencilEnabled;
|
||||
u32 enabledClipPlanes; // Bitfield of enabled clip planes
|
||||
|
||||
// Colour/depth masks
|
||||
bool redMask, greenMask, blueMask, alphaMask;
|
||||
bool depthMask;
|
||||
|
||||
GLuint stencilMask;
|
||||
GLuint boundVAO;
|
||||
GLuint boundVBO;
|
||||
GLuint currentProgram;
|
||||
|
||||
GLenum depthFunc;
|
||||
GLenum logicOp;
|
||||
|
||||
void reset();
|
||||
void resetBlend();
|
||||
void resetClipping();
|
||||
void resetColourMask();
|
||||
void resetDepth();
|
||||
void resetVAO();
|
||||
void resetVBO();
|
||||
void resetProgram();
|
||||
void resetScissor();
|
||||
void resetStencil();
|
||||
|
||||
void enableDepth() {
|
||||
if (!depthEnabled) {
|
||||
|
@ -83,6 +95,70 @@ struct GLStateManager {
|
|||
}
|
||||
}
|
||||
|
||||
void enableStencil() {
|
||||
if (!stencilEnabled) {
|
||||
stencilEnabled = true;
|
||||
OpenGL::enableStencil();
|
||||
}
|
||||
}
|
||||
|
||||
void disableStencil() {
|
||||
if (stencilEnabled) {
|
||||
stencilEnabled = false;
|
||||
OpenGL::disableStencil();
|
||||
}
|
||||
}
|
||||
|
||||
void enableLogicOp() {
|
||||
if (!logicOpEnabled) {
|
||||
logicOpEnabled = true;
|
||||
OpenGL::enableLogicOp();
|
||||
}
|
||||
}
|
||||
|
||||
void disableLogicOp() {
|
||||
if (logicOpEnabled) {
|
||||
logicOpEnabled = false;
|
||||
OpenGL::disableLogicOp();
|
||||
}
|
||||
}
|
||||
|
||||
void setLogicOp(GLenum op) {
|
||||
if (logicOp != op) {
|
||||
logicOp = op;
|
||||
OpenGL::setLogicOp(op);
|
||||
}
|
||||
}
|
||||
|
||||
void enableClipPlane(GLuint index) {
|
||||
if (index >= clipPlaneCount) [[unlikely]] {
|
||||
Helpers::panic("Enabled invalid clipping plane %d\n", index);
|
||||
}
|
||||
|
||||
if ((enabledClipPlanes & (1 << index)) == 0) {
|
||||
enabledClipPlanes |= 1 << index; // Enable relevant bit in clipping plane bitfield
|
||||
OpenGL::enableClipPlane(index); // Enable plane
|
||||
}
|
||||
}
|
||||
|
||||
void disableClipPlane(GLuint index) {
|
||||
if (index >= clipPlaneCount) [[unlikely]] {
|
||||
Helpers::panic("Disabled invalid clipping plane %d\n", index);
|
||||
}
|
||||
|
||||
if ((enabledClipPlanes & (1 << index)) != 0) {
|
||||
enabledClipPlanes ^= 1 << index; // Disable relevant bit in bitfield by flipping it
|
||||
OpenGL::disableClipPlane(index); // Disable plane
|
||||
}
|
||||
}
|
||||
|
||||
void setStencilMask(GLuint mask) {
|
||||
if (stencilMask != mask) {
|
||||
stencilMask = mask;
|
||||
OpenGL::setStencilMask(mask);
|
||||
}
|
||||
}
|
||||
|
||||
void bindVAO(GLuint handle) {
|
||||
if (boundVAO != handle) {
|
||||
boundVAO = handle;
|
||||
|
|
|
@ -333,18 +333,18 @@ namespace OpenGL {
|
|||
void bind(FramebufferTypes target) const { bind(static_cast<GLenum>(target)); }
|
||||
void free() { glDeleteFramebuffers(1, &m_handle); }
|
||||
|
||||
void createWithTexture(Texture& tex, GLenum mode = GL_FRAMEBUFFER, GLenum textureType = GL_TEXTURE_2D) {
|
||||
void createWithTexture(Texture& tex, GLenum mode = GL_FRAMEBUFFER, GLenum attachment = GL_COLOR_ATTACHMENT0, GLenum textureType = GL_TEXTURE_2D) {
|
||||
m_textureType = textureType;
|
||||
create();
|
||||
bind(mode);
|
||||
glFramebufferTexture2D(mode, GL_COLOR_ATTACHMENT0, textureType, tex.handle(), 0);
|
||||
glFramebufferTexture2D(mode, attachment, textureType, tex.handle(), 0);
|
||||
}
|
||||
|
||||
void createWithReadTexture(Texture& tex, GLenum textureType = GL_TEXTURE_2D) {
|
||||
createWithTexture(tex, GL_READ_FRAMEBUFFER, textureType);
|
||||
void createWithReadTexture(Texture& tex, GLenum attachment = GL_COLOR_ATTACHMENT0, GLenum textureType = GL_TEXTURE_2D) {
|
||||
createWithTexture(tex, GL_READ_FRAMEBUFFER, attachment, textureType);
|
||||
}
|
||||
void createWithDrawTexture(Texture& tex, GLenum textureType = GL_TEXTURE_2D) {
|
||||
createWithTexture(tex, GL_DRAW_FRAMEBUFFER, textureType);
|
||||
void createWithDrawTexture(Texture& tex, GLenum attachment = GL_COLOR_ATTACHMENT0, GLenum textureType = GL_TEXTURE_2D) {
|
||||
createWithTexture(tex, GL_DRAW_FRAMEBUFFER, attachment, textureType);
|
||||
}
|
||||
|
||||
void createWithTextureMSAA(Texture& tex, GLenum mode = GL_FRAMEBUFFER) {
|
||||
|
@ -497,40 +497,45 @@ namespace OpenGL {
|
|||
};
|
||||
|
||||
static void setClearColor(float val) { glClearColor(val, val, val, val); }
|
||||
static void setClearColor(float r, float g, float b, float a) { glClearColor(r, g, b, a); }
|
||||
static void setClearDepth(float depth) { glClearDepthf(depth); }
|
||||
static void setClearStencil(GLint stencil) { glClearStencil(stencil); }
|
||||
static void clearColor() { glClear(GL_COLOR_BUFFER_BIT); }
|
||||
static void clearDepth() { glClear(GL_DEPTH_BUFFER_BIT); }
|
||||
static void clearStencil() { glClear(GL_STENCIL_BUFFER_BIT); }
|
||||
static void clearColorAndDepth() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); }
|
||||
static void clearColorAndStencil() { glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); }
|
||||
static void clearDepthAndStencil() { glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); }
|
||||
static void clearAll() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); }
|
||||
static void setClearColor(float r, float g, float b, float a) { glClearColor(r, g, b, a); }
|
||||
static void setClearDepth(float depth) { glClearDepthf(depth); }
|
||||
static void setClearStencil(GLint stencil) { glClearStencil(stencil); }
|
||||
static void clearColor() { glClear(GL_COLOR_BUFFER_BIT); }
|
||||
static void clearDepth() { glClear(GL_DEPTH_BUFFER_BIT); }
|
||||
static void clearStencil() { glClear(GL_STENCIL_BUFFER_BIT); }
|
||||
static void clearColorAndDepth() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); }
|
||||
static void clearColorAndStencil() { glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); }
|
||||
static void clearDepthAndStencil() { glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); }
|
||||
static void clearAll() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); }
|
||||
|
||||
static void setViewport(GLsizei width, GLsizei height) { glViewport(0, 0, width, height); }
|
||||
static void setViewport(GLsizei x, GLsizei y, GLsizei width, GLsizei height) { glViewport(x, y, width, height); }
|
||||
static void setScissor(GLsizei width, GLsizei height) { glScissor(0, 0, width, height); }
|
||||
static void setScissor(GLsizei x, GLsizei y, GLsizei width, GLsizei height) { glScissor(x, y, width, height); }
|
||||
static void setStencilMask(GLuint mask) { glStencilMask(mask); }
|
||||
static void setViewport(GLsizei width, GLsizei height) { glViewport(0, 0, width, height); }
|
||||
static void setViewport(GLsizei x, GLsizei y, GLsizei width, GLsizei height) { glViewport(x, y, width, height); }
|
||||
static void setScissor(GLsizei width, GLsizei height) { glScissor(0, 0, width, height); }
|
||||
static void setScissor(GLsizei x, GLsizei y, GLsizei width, GLsizei height) { glScissor(x, y, width, height); }
|
||||
static void setStencilMask(GLuint mask) { glStencilMask(mask); }
|
||||
|
||||
static void bindScreenFramebuffer() { glBindFramebuffer(GL_FRAMEBUFFER, 0); }
|
||||
static void enableScissor() { glEnable(GL_SCISSOR_TEST); }
|
||||
static void disableScissor() { glDisable(GL_SCISSOR_TEST); }
|
||||
static void enableBlend() { glEnable(GL_BLEND); }
|
||||
static void disableBlend() { glDisable(GL_BLEND); }
|
||||
static void enableDepth() { glEnable(GL_DEPTH_TEST); }
|
||||
static void disableDepth() { glDisable(GL_DEPTH_TEST); }
|
||||
static void enableStencil() { glEnable(GL_STENCIL_TEST); }
|
||||
static void disableStencil() { glDisable(GL_STENCIL_TEST); }
|
||||
static void bindScreenFramebuffer() { glBindFramebuffer(GL_FRAMEBUFFER, 0); }
|
||||
static void enableScissor() { glEnable(GL_SCISSOR_TEST); }
|
||||
static void disableScissor() { glDisable(GL_SCISSOR_TEST); }
|
||||
static void enableBlend() { glEnable(GL_BLEND); }
|
||||
static void disableBlend() { glDisable(GL_BLEND); }
|
||||
static void enableLogicOp() { glEnable(GL_COLOR_LOGIC_OP); }
|
||||
static void disableLogicOp() { glDisable(GL_COLOR_LOGIC_OP); }
|
||||
static void enableDepth() { glEnable(GL_DEPTH_TEST); }
|
||||
static void disableDepth() { glDisable(GL_DEPTH_TEST); }
|
||||
static void enableStencil() { glEnable(GL_STENCIL_TEST); }
|
||||
static void disableStencil() { glDisable(GL_STENCIL_TEST); }
|
||||
|
||||
static void enableClipPlane(GLuint index) { glEnable(GL_CLIP_DISTANCE0 + index); }
|
||||
static void enableClipPlane(GLuint index) { glEnable(GL_CLIP_DISTANCE0 + index); }
|
||||
static void disableClipPlane(GLuint index) { glDisable(GL_CLIP_DISTANCE0 + index); }
|
||||
|
||||
static void setDepthFunc(DepthFunc func) { glDepthFunc(static_cast<GLenum>(func)); }
|
||||
static void setDepthFunc(DepthFunc func) { glDepthFunc(static_cast<GLenum>(func)); }
|
||||
static void setColourMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) { glColorMask(r, g, b, a); }
|
||||
static void setDepthMask(GLboolean mask) { glDepthMask(mask); }
|
||||
|
||||
// TODO: Add a proper enum for this
|
||||
static void setLogicOp(GLenum op) { glLogicOp(op); }
|
||||
|
||||
enum Primitives {
|
||||
Triangle = GL_TRIANGLES,
|
||||
Triangles = Triangle,
|
||||
|
|
|
@ -61,6 +61,7 @@ class RendererGL final : public Renderer {
|
|||
|
||||
MAKE_LOG_FUNCTION(log, rendererLogger)
|
||||
void setupBlending();
|
||||
void setupStencilTest(bool stencilEnable);
|
||||
void bindDepthBuffer();
|
||||
void setupTextureEnvState();
|
||||
void bindTexturesToSlots();
|
||||
|
@ -79,4 +80,4 @@ class RendererGL final : public Renderer {
|
|||
|
||||
// Take a screenshot of the screen and store it in a file
|
||||
void screenshot(const std::string& name) override;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -86,6 +86,7 @@ struct DepthBuffer {
|
|||
Interval<u32> range;
|
||||
// OpenGL texture used for storing depth/stencil
|
||||
OpenGL::Texture texture;
|
||||
OpenGL::Framebuffer fbo;
|
||||
|
||||
DepthBuffer() : valid(false) {}
|
||||
|
||||
|
@ -127,6 +128,11 @@ struct DepthBuffer {
|
|||
texture.setMagFilter(OpenGL::Nearest);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, prevTexture);
|
||||
|
||||
fbo.createWithDrawTexture(texture, fmt == GL_DEPTH_STENCIL ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
Helpers::panic("Incomplete framebuffer");
|
||||
}
|
||||
|
||||
void free() {
|
||||
|
@ -144,4 +150,4 @@ struct DepthBuffer {
|
|||
size_t sizeInBytes() {
|
||||
return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -2,7 +2,20 @@
|
|||
|
||||
void GLStateManager::resetBlend() {
|
||||
blendEnabled = false;
|
||||
logicOpEnabled = false;
|
||||
logicOp = GL_COPY;
|
||||
|
||||
OpenGL::disableBlend();
|
||||
OpenGL::disableLogicOp();
|
||||
OpenGL::setLogicOp(GL_COPY);
|
||||
}
|
||||
|
||||
void GLStateManager::resetClipping() {
|
||||
// Disable all (supported) clip planes
|
||||
enabledClipPlanes = 0;
|
||||
for (int i = 0; i < clipPlaneCount; i++) {
|
||||
OpenGL::disableClipPlane(i);
|
||||
}
|
||||
}
|
||||
|
||||
void GLStateManager::resetColourMask() {
|
||||
|
@ -26,6 +39,14 @@ void GLStateManager::resetScissor() {
|
|||
OpenGL::setScissor(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void GLStateManager::resetStencil() {
|
||||
stencilEnabled = false;
|
||||
stencilMask = 0xff;
|
||||
|
||||
OpenGL::disableStencil();
|
||||
OpenGL::setStencilMask(0xff);
|
||||
}
|
||||
|
||||
void GLStateManager::resetVAO() {
|
||||
boundVAO = 0;
|
||||
glBindVertexArray(0);
|
||||
|
@ -43,6 +64,7 @@ void GLStateManager::resetProgram() {
|
|||
|
||||
void GLStateManager::reset() {
|
||||
resetBlend();
|
||||
resetClipping();
|
||||
resetColourMask();
|
||||
resetDepth();
|
||||
|
||||
|
@ -50,4 +72,5 @@ void GLStateManager::reset() {
|
|||
resetVBO();
|
||||
resetProgram();
|
||||
resetScissor();
|
||||
resetStencil();
|
||||
}
|
|
@ -149,8 +149,6 @@ void RendererGL::initGraphicsContext(SDL_Window* window) {
|
|||
|
||||
// Set up the OpenGL blending context to match the emulated PICA
|
||||
void RendererGL::setupBlending() {
|
||||
const bool blendingEnabled = (regs[PICA::InternalRegs::ColourOperation] & (1 << 8)) != 0;
|
||||
|
||||
// Map of PICA blending equations to OpenGL blending equations. The unused blending equations are equivalent to equation 0 (add)
|
||||
static constexpr std::array<GLenum, 8> blendingEquations = {
|
||||
GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT, GL_MIN, GL_MAX, GL_FUNC_ADD, GL_FUNC_ADD, GL_FUNC_ADD,
|
||||
|
@ -176,10 +174,23 @@ void RendererGL::setupBlending() {
|
|||
GL_ONE,
|
||||
};
|
||||
|
||||
if (!blendingEnabled) {
|
||||
gl.disableBlend();
|
||||
static constexpr std::array<GLenum, 16> logicOps = {
|
||||
GL_CLEAR, GL_AND, GL_AND_REVERSE, GL_COPY, GL_SET, GL_COPY_INVERTED, GL_NOOP, GL_INVERT,
|
||||
GL_NAND, GL_OR, GL_NOR, GL_XOR, GL_EQUIV, GL_AND_INVERTED, GL_OR_REVERSE, GL_OR_INVERTED,
|
||||
};
|
||||
|
||||
// Shows if blending is enabled. If it is not enabled, then logic ops are enabled instead
|
||||
const bool blendingEnabled = (regs[PICA::InternalRegs::ColourOperation] & (1 << 8)) != 0;
|
||||
|
||||
if (!blendingEnabled) { // Logic ops are enabled
|
||||
const u32 logicOp = getBits<0, 4>(regs[PICA::InternalRegs::LogicOp]);
|
||||
gl.setLogicOp(logicOps[logicOp]);
|
||||
|
||||
// If logic ops are enabled we don't need to disable blending because they override it
|
||||
gl.enableLogicOp();
|
||||
} else {
|
||||
gl.enableBlend();
|
||||
gl.disableLogicOp();
|
||||
|
||||
// Get blending equations
|
||||
const u32 blendControl = regs[PICA::InternalRegs::BlendFunc];
|
||||
|
@ -205,6 +216,55 @@ void RendererGL::setupBlending() {
|
|||
}
|
||||
}
|
||||
|
||||
void RendererGL::setupStencilTest(bool stencilEnable) {
|
||||
if (!stencilEnable) {
|
||||
gl.disableStencil();
|
||||
return;
|
||||
}
|
||||
|
||||
static constexpr std::array<GLenum, 8> stencilFuncs = {
|
||||
GL_NEVER,
|
||||
GL_ALWAYS,
|
||||
GL_EQUAL,
|
||||
GL_NOTEQUAL,
|
||||
GL_LESS,
|
||||
GL_LEQUAL,
|
||||
GL_GREATER,
|
||||
GL_GEQUAL
|
||||
};
|
||||
gl.enableStencil();
|
||||
|
||||
const u32 stencilConfig = regs[PICA::InternalRegs::StencilTest];
|
||||
const u32 stencilFunc = getBits<4, 3>(stencilConfig);
|
||||
const s32 reference = s8(getBits<16, 8>(stencilConfig)); // Signed reference value
|
||||
const u32 stencilRefMask = getBits<24, 8>(stencilConfig);
|
||||
|
||||
const bool stencilWrite = regs[PICA::InternalRegs::DepthBufferWrite];
|
||||
const u32 stencilBufferMask = stencilWrite ? getBits<8, 8>(stencilConfig) : 0;
|
||||
|
||||
// TODO: Throw stencilFunc/stencilOp to the GL state manager
|
||||
glStencilFunc(stencilFuncs[stencilFunc], reference, stencilRefMask);
|
||||
gl.setStencilMask(stencilBufferMask);
|
||||
|
||||
static constexpr std::array<GLenum, 8> stencilOps = {
|
||||
GL_KEEP,
|
||||
GL_ZERO,
|
||||
GL_REPLACE,
|
||||
GL_INCR,
|
||||
GL_DECR,
|
||||
GL_INVERT,
|
||||
GL_INCR_WRAP,
|
||||
GL_DECR_WRAP
|
||||
};
|
||||
const u32 stencilOpConfig = regs[PICA::InternalRegs::StencilOp];
|
||||
const u32 stencilFailOp = getBits<0, 3>(stencilOpConfig);
|
||||
const u32 depthFailOp = getBits<4, 3>(stencilOpConfig);
|
||||
const u32 passOp = getBits<8, 3>(stencilOpConfig);
|
||||
|
||||
glStencilOp(stencilOps[stencilFailOp], stencilOps[depthFailOp], stencilOps[passOp]);
|
||||
}
|
||||
|
||||
|
||||
void RendererGL::setupTextureEnvState() {
|
||||
// TODO: Only update uniforms when the TEV config changed. Use an UBO potentially.
|
||||
|
||||
|
@ -302,9 +362,9 @@ void RendererGL::drawVertices(PICA::PrimType primType, std::span<const Vertex> v
|
|||
gl.bindVAO(vao);
|
||||
gl.useProgram(triangleProgram);
|
||||
|
||||
OpenGL::enableClipPlane(0); // Clipping plane 0 is always enabled
|
||||
gl.enableClipPlane(0); // Clipping plane 0 is always enabled
|
||||
if (regs[PICA::InternalRegs::ClipEnable] & 1) {
|
||||
OpenGL::enableClipPlane(1);
|
||||
gl.enableClipPlane(1);
|
||||
}
|
||||
|
||||
setupBlending();
|
||||
|
@ -312,6 +372,7 @@ void RendererGL::drawVertices(PICA::PrimType primType, std::span<const Vertex> v
|
|||
poop.bind(OpenGL::DrawAndReadFramebuffer);
|
||||
|
||||
const u32 depthControl = regs[PICA::InternalRegs::DepthAndColorMask];
|
||||
const bool depthWrite = regs[PICA::InternalRegs::DepthBufferWrite];
|
||||
const bool depthEnable = depthControl & 1;
|
||||
const bool depthWriteEnable = getBit<12>(depthControl);
|
||||
const int depthFunc = getBits<4, 3>(depthControl);
|
||||
|
@ -356,11 +417,14 @@ void RendererGL::drawVertices(PICA::PrimType primType, std::span<const Vertex> v
|
|||
GLsizei viewportHeight = GLsizei(f24::fromRaw(regs[PICA::InternalRegs::ViewportHeight] & 0xffffff).toFloat32() * 2.0f);
|
||||
OpenGL::setViewport(viewportWidth, viewportHeight);
|
||||
|
||||
const u32 stencilConfig = regs[PICA::InternalRegs::StencilTest];
|
||||
const bool stencilEnable = getBit<0>(stencilConfig);
|
||||
|
||||
// Note: The code below must execute after we've bound the colour buffer & its framebuffer
|
||||
// Because it attaches a depth texture to the aforementioned colour buffer
|
||||
if (depthEnable) {
|
||||
gl.enableDepth();
|
||||
gl.setDepthMask(depthWriteEnable ? GL_TRUE : GL_FALSE);
|
||||
gl.setDepthMask(depthWriteEnable && depthWrite ? GL_TRUE : GL_FALSE);
|
||||
gl.setDepthFunc(depthModes[depthFunc]);
|
||||
bindDepthBuffer();
|
||||
} else {
|
||||
|
@ -371,16 +435,19 @@ void RendererGL::drawVertices(PICA::PrimType primType, std::span<const Vertex> v
|
|||
bindDepthBuffer();
|
||||
} else {
|
||||
gl.disableDepth();
|
||||
|
||||
if (stencilEnable) {
|
||||
bindDepthBuffer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setupStencilTest(stencilEnable);
|
||||
|
||||
vbo.bufferVertsSub(vertices);
|
||||
OpenGL::draw(primitiveTopology, GLsizei(vertices.size()));
|
||||
}
|
||||
|
||||
constexpr u32 topScreenBuffer = 0x1f000000;
|
||||
constexpr u32 bottomScreenBuffer = 0x1f05dc00;
|
||||
|
||||
void RendererGL::display() {
|
||||
gl.disableScissor();
|
||||
|
||||
|
@ -390,25 +457,50 @@ void RendererGL::display() {
|
|||
}
|
||||
|
||||
void RendererGL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) {
|
||||
return;
|
||||
log("GPU: Clear buffer\nStart: %08X End: %08X\nValue: %08X Control: %08X\n", startAddress, endAddress, value, control);
|
||||
gl.disableScissor();
|
||||
|
||||
const float r = float(getBits<24, 8>(value)) / 255.0f;
|
||||
const float g = float(getBits<16, 8>(value)) / 255.0f;
|
||||
const float b = float(getBits<8, 8>(value)) / 255.0f;
|
||||
const float a = float(value & 0xff) / 255.0f;
|
||||
|
||||
if (startAddress == topScreenBuffer) {
|
||||
log("GPU: Cleared top screen\n");
|
||||
} else if (startAddress == bottomScreenBuffer) {
|
||||
log("GPU: Tried to clear bottom screen\n");
|
||||
const auto color = colourBufferCache.findFromAddress(startAddress);
|
||||
if (color) {
|
||||
const float r = getBits<24, 8>(value) / 255.0f;
|
||||
const float g = getBits<16, 8>(value) / 255.0f;
|
||||
const float b = getBits<8, 8>(value) / 255.0f;
|
||||
const float a = (value & 0xff) / 255.0f;
|
||||
color->get().fbo.bind(OpenGL::DrawFramebuffer);
|
||||
gl.setColourMask(true, true, true, true);
|
||||
OpenGL::setClearColor(r, g, b, a);
|
||||
OpenGL::clearColor();
|
||||
return;
|
||||
} else {
|
||||
log("GPU: Clearing some unknown buffer\n");
|
||||
}
|
||||
|
||||
OpenGL::setClearColor(r, g, b, a);
|
||||
OpenGL::clearColor();
|
||||
const auto depth = depthBufferCache.findFromAddress(startAddress);
|
||||
if (depth) {
|
||||
depth->get().fbo.bind(OpenGL::DrawFramebuffer);
|
||||
|
||||
float depthVal;
|
||||
const auto format = depth->get().format;
|
||||
if (format == DepthFmt::Depth16) {
|
||||
depthVal = (value & 0xffff) / 65535.0f;
|
||||
} else {
|
||||
depthVal = (value & 0xffffff) / 16777215.0f;
|
||||
}
|
||||
|
||||
gl.setDepthMask(true);
|
||||
OpenGL::setClearDepth(depthVal);
|
||||
|
||||
if (format == DepthFmt::Depth24Stencil8) {
|
||||
const u8 stencil = (value >> 24);
|
||||
gl.setStencilMask(0xff);
|
||||
OpenGL::setClearStencil(stencil);
|
||||
OpenGL::clearDepthAndStencil();
|
||||
} else {
|
||||
OpenGL::clearDepth();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
log("[RendererGL::ClearBuffer] No buffer found!\n");
|
||||
}
|
||||
|
||||
OpenGL::Framebuffer RendererGL::getColourFBO() {
|
||||
|
@ -474,14 +566,16 @@ void RendererGL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u
|
|||
screenFramebuffer.bind(OpenGL::DrawFramebuffer);
|
||||
|
||||
gl.disableBlend();
|
||||
gl.disableLogicOp();
|
||||
gl.disableDepth();
|
||||
gl.disableScissor();
|
||||
gl.disableStencil();
|
||||
gl.setColourMask(true, true, true, true);
|
||||
gl.useProgram(displayProgram);
|
||||
gl.bindVAO(dummyVAO);
|
||||
|
||||
OpenGL::disableClipPlane(0);
|
||||
OpenGL::disableClipPlane(1);
|
||||
gl.disableClipPlane(0);
|
||||
gl.disableClipPlane(1);
|
||||
|
||||
// Hack: Detect whether we are writing to the top or bottom screen by checking output gap and drawing to the proper part of the output texture
|
||||
// We consider output gap == 320 to mean bottom, and anything else to mean top
|
||||
|
|
|
@ -299,6 +299,28 @@ void GPUService::processCommandBuffer() {
|
|||
}
|
||||
}
|
||||
|
||||
static u32 VaddrToPaddr(u32 addr) {
|
||||
if (addr >= VirtualAddrs::VramStart && addr < (VirtualAddrs::VramStart + VirtualAddrs::VramSize)) [[likely]] {
|
||||
return addr - VirtualAddrs::VramStart + PhysicalAddrs::VRAM;
|
||||
}
|
||||
|
||||
else if (addr >= VirtualAddrs::LinearHeapStartOld && addr < VirtualAddrs::LinearHeapEndOld) {
|
||||
return addr - VirtualAddrs::LinearHeapStartOld + PhysicalAddrs::FCRAM;
|
||||
}
|
||||
|
||||
else if (addr >= VirtualAddrs::LinearHeapStartNew && addr < VirtualAddrs::LinearHeapEndNew) {
|
||||
return addr - VirtualAddrs::LinearHeapStartNew + PhysicalAddrs::FCRAM;
|
||||
}
|
||||
|
||||
else if (addr == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Helpers::warn("[GSP::GPU VaddrToPaddr] Unknown virtual address %08X", addr);
|
||||
// Obviously garbage address
|
||||
return 0xF3310932;
|
||||
}
|
||||
|
||||
// Fill 2 GPU framebuffers, buf0 and buf1, using a specific word value
|
||||
void GPUService::memoryFill(u32* cmd) {
|
||||
u32 control = cmd[7];
|
||||
|
@ -316,38 +338,16 @@ void GPUService::memoryFill(u32* cmd) {
|
|||
u32 control1 = control >> 16;
|
||||
|
||||
if (start0 != 0) {
|
||||
gpu.clearBuffer(start0, end0, value0, control0);
|
||||
gpu.clearBuffer(VaddrToPaddr(start0), VaddrToPaddr(end0), value0, control0);
|
||||
requestInterrupt(GPUInterrupt::PSC0);
|
||||
}
|
||||
|
||||
if (start1 != 0) {
|
||||
gpu.clearBuffer(start1, end1, value1, control1);
|
||||
gpu.clearBuffer(VaddrToPaddr(start1), VaddrToPaddr(end1), value1, control1);
|
||||
requestInterrupt(GPUInterrupt::PSC1);
|
||||
}
|
||||
}
|
||||
|
||||
static u32 VaddrToPaddr(u32 addr) {
|
||||
if (addr >= VirtualAddrs::VramStart && addr < (VirtualAddrs::VramStart + VirtualAddrs::VramSize)) [[likely]] {
|
||||
return addr - VirtualAddrs::VramStart + PhysicalAddrs::VRAM;
|
||||
}
|
||||
|
||||
else if (addr >= VirtualAddrs::LinearHeapStartOld && addr < VirtualAddrs::LinearHeapEndOld) {
|
||||
return addr - VirtualAddrs::LinearHeapStartOld + PhysicalAddrs::FCRAM;
|
||||
}
|
||||
|
||||
else if (addr >= VirtualAddrs::LinearHeapStartNew && addr < VirtualAddrs::LinearHeapEndNew) {
|
||||
return addr - VirtualAddrs::LinearHeapStartNew + PhysicalAddrs::FCRAM;
|
||||
}
|
||||
|
||||
else if (addr == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Helpers::warn("[GSP::GPU VaddrToPaddr] Unknown virtual address %08X", addr);
|
||||
// Obviously garbage address
|
||||
return 0xF3310932;
|
||||
}
|
||||
|
||||
void GPUService::triggerDisplayTransfer(u32* cmd) {
|
||||
const u32 inputAddr = VaddrToPaddr(cmd[1]);
|
||||
const u32 outputAddr = VaddrToPaddr(cmd[2]);
|
||||
|
@ -394,4 +394,4 @@ void GPUService::triggerTextureCopy(u32* cmd) {
|
|||
// This uses the transfer engine and thus needs to fire a PPF interrupt.
|
||||
// NSMB2 relies on this
|
||||
requestInterrupt(GPUInterrupt::PPF);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue