mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-09 07:35:41 +12:00
Add clear colour to GL state manager
This commit is contained in:
parent
4107a84c0d
commit
0f5c41cd69
4 changed files with 138 additions and 128 deletions
|
@ -34,6 +34,8 @@ struct GLStateManager {
|
||||||
bool redMask, greenMask, blueMask, alphaMask;
|
bool redMask, greenMask, blueMask, alphaMask;
|
||||||
bool depthMask;
|
bool depthMask;
|
||||||
|
|
||||||
|
float clearRed, clearBlue, clearGreen, clearAlpha;
|
||||||
|
|
||||||
GLuint stencilMask;
|
GLuint stencilMask;
|
||||||
GLuint boundVAO;
|
GLuint boundVAO;
|
||||||
GLuint boundVBO;
|
GLuint boundVBO;
|
||||||
|
@ -44,6 +46,7 @@ struct GLStateManager {
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void resetBlend();
|
void resetBlend();
|
||||||
|
void resetClearing();
|
||||||
void resetClipping();
|
void resetClipping();
|
||||||
void resetColourMask();
|
void resetColourMask();
|
||||||
void resetDepth();
|
void resetDepth();
|
||||||
|
@ -209,8 +212,19 @@ struct GLStateManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setClearColour(float r, float g, float b, float a) {
|
||||||
|
if (clearRed != r || clearGreen != g || clearBlue != b || clearAlpha != a) {
|
||||||
|
clearRed = r;
|
||||||
|
clearGreen = g;
|
||||||
|
clearBlue = b;
|
||||||
|
clearAlpha = a;
|
||||||
|
|
||||||
|
OpenGL::setClearColor(r, g, b, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setDepthFunc(OpenGL::DepthFunc func) { setDepthFunc(static_cast<GLenum>(func)); }
|
void setDepthFunc(OpenGL::DepthFunc func) { setDepthFunc(static_cast<GLenum>(func)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(std::is_trivially_constructible<GLStateManager>(), "OpenGL State Manager class is not trivially constructible!");
|
static_assert(std::is_trivially_constructible<GLStateManager>(), "OpenGL State Manager class is not trivially constructible!");
|
||||||
static_assert(std::is_trivially_destructible<GLStateManager>(), "OpenGL State Manager class is not trivially destructible!");
|
static_assert(std::is_trivially_destructible<GLStateManager>(), "OpenGL State Manager class is not trivially destructible!");
|
|
@ -9,83 +9,63 @@ template <typename T>
|
||||||
using Interval = boost::icl::right_open_interval<T>;
|
using Interval = boost::icl::right_open_interval<T>;
|
||||||
|
|
||||||
struct ColourBuffer {
|
struct ColourBuffer {
|
||||||
u32 location;
|
u32 location;
|
||||||
PICA::ColorFmt format;
|
PICA::ColorFmt format;
|
||||||
OpenGL::uvec2 size;
|
OpenGL::uvec2 size;
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
// Range of VRAM taken up by buffer
|
// Range of VRAM taken up by buffer
|
||||||
Interval<u32> range;
|
Interval<u32> range;
|
||||||
// OpenGL resources allocated to buffer
|
// OpenGL resources allocated to buffer
|
||||||
OpenGL::Texture texture;
|
OpenGL::Texture texture;
|
||||||
OpenGL::Framebuffer fbo;
|
OpenGL::Framebuffer fbo;
|
||||||
|
|
||||||
GLenum internalFormat;
|
ColourBuffer() : valid(false) {}
|
||||||
GLenum fmt;
|
|
||||||
GLenum type;
|
|
||||||
|
|
||||||
ColourBuffer() : valid(false) {}
|
ColourBuffer(u32 loc, PICA::ColorFmt format, u32 x, u32 y, bool valid = true) : location(loc), format(format), size({x, y}), valid(valid) {
|
||||||
|
u64 endLoc = (u64)loc + sizeInBytes();
|
||||||
ColourBuffer(u32 loc, PICA::ColorFmt format, u32 x, u32 y, bool valid = true)
|
// Check if start and end are valid here
|
||||||
: location(loc), format(format), size({x, y}), valid(valid) {
|
range = Interval<u32>(loc, (u32)endLoc);
|
||||||
|
}
|
||||||
u64 endLoc = (u64)loc + sizeInBytes();
|
|
||||||
// Check if start and end are valid here
|
|
||||||
range = Interval<u32>(loc, (u32)endLoc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void allocate() {
|
void allocate() {
|
||||||
// Internal formats for the texture based on format
|
// Create texture for the FBO, setting up filters and the like
|
||||||
static constexpr std::array<GLenum, 5> internalFormats = {
|
// Reading back the current texture is slow, but allocate calls should be few and far between.
|
||||||
GL_RGBA8, GL_RGB8, GL_RGB5_A1, GL_RGB565, GL_RGBA4
|
// If this becomes a bottleneck, we can fix it semi-easily
|
||||||
};
|
auto prevTexture = OpenGL::getTex2D();
|
||||||
|
texture.create(size.x(), size.y(), GL_RGBA8);
|
||||||
// Format of the texture
|
texture.bind();
|
||||||
static constexpr std::array<GLenum, 5> formats = {
|
texture.setMinFilter(OpenGL::Linear);
|
||||||
GL_RGBA, GL_BGR, GL_RGBA, GL_RGB, GL_RGBA,
|
texture.setMagFilter(OpenGL::Linear);
|
||||||
};
|
glBindTexture(GL_TEXTURE_2D, prevTexture);
|
||||||
|
|
||||||
static constexpr std::array<GLenum, 5> types = {
|
|
||||||
GL_UNSIGNED_INT_8_8_8_8, GL_UNSIGNED_BYTE, GL_UNSIGNED_SHORT_5_5_5_1,
|
|
||||||
GL_UNSIGNED_SHORT_5_6_5, GL_UNSIGNED_SHORT_4_4_4_4,
|
|
||||||
};
|
|
||||||
|
|
||||||
internalFormat = internalFormats[(int)format];
|
|
||||||
fmt = formats[(int)format];
|
|
||||||
type = types[(int)format];
|
|
||||||
|
|
||||||
|
|
||||||
// Create texture for the FBO, setting up filters and the like
|
|
||||||
// Reading back the current texture is slow, but allocate calls should be few and far between.
|
|
||||||
// If this becomes a bottleneck, we can fix it semi-easily
|
|
||||||
auto prevTexture = OpenGL::getTex2D();
|
|
||||||
texture.create(size.x(), size.y(), internalFormat);
|
|
||||||
texture.bind();
|
|
||||||
texture.setMinFilter(OpenGL::Linear);
|
|
||||||
texture.setMagFilter(OpenGL::Linear);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, prevTexture);
|
|
||||||
|
|
||||||
#ifdef GPU_DEBUG_INFO
|
#ifdef GPU_DEBUG_INFO
|
||||||
const auto name = Helpers::format("Surface %dx%d %s from 0x%08X", size.x(), size.y(), PICA::textureFormatToString(format), location);
|
const auto name = Helpers::format("Surface %dx%d %s from 0x%08X", size.x(), size.y(), PICA::textureFormatToString(format), location);
|
||||||
OpenGL::setObjectLabel(GL_TEXTURE, texture.handle(), name.c_str());
|
OpenGL::setObjectLabel(GL_TEXTURE, texture.handle(), name.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fbo.createWithDrawTexture(texture);
|
fbo.createWithDrawTexture(texture);
|
||||||
fbo.bind(OpenGL::DrawAndReadFramebuffer);
|
fbo.bind(OpenGL::DrawAndReadFramebuffer);
|
||||||
|
|
||||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
Helpers::panic("Incomplete framebuffer");
|
Helpers::panic("Incomplete framebuffer");
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: This should not clear the framebuffer contents. It should load them from VRAM.
|
// TODO: This should not clear the framebuffer contents. It should load them from VRAM.
|
||||||
GLint oldViewport[4];
|
GLint oldViewport[4];
|
||||||
glGetIntegerv(GL_VIEWPORT, oldViewport);
|
GLfloat oldClearColour[4];
|
||||||
OpenGL::setViewport(size.x(), size.y());
|
|
||||||
OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0);
|
|
||||||
OpenGL::clearColor();
|
|
||||||
OpenGL::setViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void free() {
|
glGetIntegerv(GL_VIEWPORT, oldViewport);
|
||||||
|
glGetFloatv(GL_COLOR_CLEAR_VALUE, oldClearColour);
|
||||||
|
|
||||||
|
OpenGL::setViewport(size.x(), size.y());
|
||||||
|
OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
|
OpenGL::clearColor();
|
||||||
|
OpenGL::setViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
|
||||||
|
OpenGL::setClearColor(oldClearColour[0], oldClearColour[1], oldClearColour[2], oldClearColour[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free() {
|
||||||
valid = false;
|
valid = false;
|
||||||
|
|
||||||
if (texture.exists() || fbo.exists()) {
|
if (texture.exists() || fbo.exists()) {
|
||||||
|
@ -103,88 +83,93 @@ struct ColourBuffer {
|
||||||
return Math::Rect<u32>{x0, size.y() - y0, x0 + width, size.y() - height - y0};
|
return Math::Rect<u32>{x0, size.y() - y0, x0 + width, size.y() - height - y0};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matches(ColourBuffer& other) {
|
bool matches(ColourBuffer& other) {
|
||||||
return location == other.location && format == other.format &&
|
return location == other.location && format == other.format && size.x() == other.size.x() && size.y() == other.size.y();
|
||||||
size.x() == other.size.x() && size.y() == other.size.y();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
size_t sizeInBytes() {
|
size_t sizeInBytes() {
|
||||||
return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format);
|
return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DepthBuffer {
|
struct DepthBuffer {
|
||||||
u32 location;
|
u32 location;
|
||||||
PICA::DepthFmt format;
|
PICA::DepthFmt format;
|
||||||
OpenGL::uvec2 size; // Implicitly set to the size of the framebuffer
|
OpenGL::uvec2 size; // Implicitly set to the size of the framebuffer
|
||||||
bool valid;
|
bool valid;
|
||||||
|
|
||||||
// Range of VRAM taken up by buffer
|
// Range of VRAM taken up by buffer
|
||||||
Interval<u32> range;
|
Interval<u32> range;
|
||||||
// OpenGL texture used for storing depth/stencil
|
// OpenGL texture used for storing depth/stencil
|
||||||
OpenGL::Texture texture;
|
OpenGL::Texture texture;
|
||||||
OpenGL::Framebuffer fbo;
|
OpenGL::Framebuffer fbo;
|
||||||
|
|
||||||
DepthBuffer() : valid(false) {}
|
DepthBuffer() : valid(false) {}
|
||||||
|
|
||||||
DepthBuffer(u32 loc, PICA::DepthFmt format, u32 x, u32 y, bool valid = true) :
|
DepthBuffer(u32 loc, PICA::DepthFmt format, u32 x, u32 y, bool valid = true) : location(loc), format(format), size({x, y}), valid(valid) {
|
||||||
location(loc), format(format), size({x, y}), valid(valid) {
|
u64 endLoc = (u64)loc + sizeInBytes();
|
||||||
|
// Check if start and end are valid here
|
||||||
|
range = Interval<u32>(loc, (u32)endLoc);
|
||||||
|
}
|
||||||
|
|
||||||
u64 endLoc = (u64)loc + sizeInBytes();
|
void allocate() {
|
||||||
// Check if start and end are valid here
|
// Create texture for the FBO, setting up filters and the like
|
||||||
range = Interval<u32>(loc, (u32)endLoc);
|
// Reading back the current texture is slow, but allocate calls should be few and far between.
|
||||||
}
|
// If this becomes a bottleneck, we can fix it semi-easily
|
||||||
|
auto prevTexture = OpenGL::getTex2D();
|
||||||
|
|
||||||
void allocate() {
|
// Internal formats for the texture based on format
|
||||||
// Create texture for the FBO, setting up filters and the like
|
static constexpr std::array<GLenum, 4> internalFormats = {
|
||||||
// Reading back the current texture is slow, but allocate calls should be few and far between.
|
GL_DEPTH_COMPONENT16,
|
||||||
// If this becomes a bottleneck, we can fix it semi-easily
|
GL_DEPTH_COMPONENT24,
|
||||||
auto prevTexture = OpenGL::getTex2D();
|
GL_DEPTH_COMPONENT24,
|
||||||
|
GL_DEPTH24_STENCIL8,
|
||||||
|
};
|
||||||
|
|
||||||
// Internal formats for the texture based on format
|
// Format of the texture
|
||||||
static constexpr std::array<GLenum, 4> internalFormats = {
|
static constexpr std::array<GLenum, 4> formats = {
|
||||||
GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT24, GL_DEPTH24_STENCIL8
|
GL_DEPTH_COMPONENT,
|
||||||
};
|
GL_DEPTH_COMPONENT,
|
||||||
|
GL_DEPTH_COMPONENT,
|
||||||
|
GL_DEPTH_STENCIL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::array<GLenum, 4> types = {
|
||||||
|
GL_UNSIGNED_SHORT,
|
||||||
|
GL_UNSIGNED_INT,
|
||||||
|
GL_UNSIGNED_INT,
|
||||||
|
GL_UNSIGNED_INT_24_8,
|
||||||
|
};
|
||||||
|
|
||||||
// Format of the texture
|
auto internalFormat = internalFormats[(int)format];
|
||||||
static constexpr std::array<GLenum, 4> formats = {
|
auto fmt = formats[(int)format];
|
||||||
GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT, GL_DEPTH_STENCIL
|
auto type = types[(int)format];
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr std::array<GLenum, 4> types = {
|
texture.createDSTexture(size.x(), size.y(), internalFormat, fmt, nullptr, type, GL_TEXTURE_2D);
|
||||||
GL_UNSIGNED_SHORT, GL_UNSIGNED_INT, GL_UNSIGNED_INT, GL_UNSIGNED_INT_24_8
|
texture.bind();
|
||||||
};
|
texture.setMinFilter(OpenGL::Nearest);
|
||||||
|
texture.setMagFilter(OpenGL::Nearest);
|
||||||
|
|
||||||
auto internalFormat = internalFormats[(int)format];
|
glBindTexture(GL_TEXTURE_2D, prevTexture);
|
||||||
auto fmt = formats[(int)format];
|
fbo.createWithDrawTexture(texture, fmt == GL_DEPTH_STENCIL ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT);
|
||||||
auto type = types[(int)format];
|
|
||||||
|
|
||||||
texture.createDSTexture(size.x(), size.y(), internalFormat, fmt, nullptr, type, GL_TEXTURE_2D);
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||||
texture.bind();
|
|
||||||
texture.setMinFilter(OpenGL::Nearest);
|
|
||||||
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");
|
Helpers::panic("Incomplete framebuffer");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void free() {
|
void free() {
|
||||||
valid = false;
|
valid = false;
|
||||||
if (texture.exists()) {
|
if (texture.exists()) {
|
||||||
texture.free();
|
texture.free();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matches(DepthBuffer& other) {
|
bool matches(DepthBuffer& other) {
|
||||||
return location == other.location && format == other.format &&
|
return location == other.location && format == other.format && size.x() == other.size.x() && size.y() == other.size.y();
|
||||||
size.x() == other.size.x() && size.y() == other.size.y();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
size_t sizeInBytes() {
|
size_t sizeInBytes() {
|
||||||
return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format);
|
return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,15 @@ void GLStateManager::resetBlend() {
|
||||||
OpenGL::setLogicOp(GL_COPY);
|
OpenGL::setLogicOp(GL_COPY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLStateManager::resetClearing() {
|
||||||
|
clearRed = 0.f;
|
||||||
|
clearBlue = 0.f;
|
||||||
|
clearGreen = 0.f;
|
||||||
|
clearAlpha = 1.f;
|
||||||
|
|
||||||
|
OpenGL::setClearColor(clearRed, clearBlue, clearGreen, clearAlpha);
|
||||||
|
}
|
||||||
|
|
||||||
void GLStateManager::resetClipping() {
|
void GLStateManager::resetClipping() {
|
||||||
// Disable all (supported) clip planes
|
// Disable all (supported) clip planes
|
||||||
enabledClipPlanes = 0;
|
enabledClipPlanes = 0;
|
||||||
|
@ -64,6 +73,7 @@ void GLStateManager::resetProgram() {
|
||||||
|
|
||||||
void GLStateManager::reset() {
|
void GLStateManager::reset() {
|
||||||
resetBlend();
|
resetBlend();
|
||||||
|
resetClearing();
|
||||||
resetClipping();
|
resetClipping();
|
||||||
resetColourMask();
|
resetColourMask();
|
||||||
resetDepth();
|
resetDepth();
|
||||||
|
|
|
@ -141,7 +141,7 @@ void RendererGL::initGraphicsContext(SDL_Window* window) {
|
||||||
GLint oldViewport[4];
|
GLint oldViewport[4];
|
||||||
glGetIntegerv(GL_VIEWPORT, oldViewport);
|
glGetIntegerv(GL_VIEWPORT, oldViewport);
|
||||||
OpenGL::setViewport(screenTextureWidth, screenTextureHeight);
|
OpenGL::setViewport(screenTextureWidth, screenTextureHeight);
|
||||||
OpenGL::setClearColor(0.0, 0.0, 0.0, 1.0);
|
gl.setClearColour(0.0, 0.0, 0.0, 1.0);
|
||||||
OpenGL::clearColor();
|
OpenGL::clearColor();
|
||||||
OpenGL::setViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
|
OpenGL::setViewport(oldViewport[0], oldViewport[1], oldViewport[2], oldViewport[3]);
|
||||||
|
|
||||||
|
@ -473,7 +473,7 @@ void RendererGL::display() {
|
||||||
auto bottomScreen = colourBufferCache.findFromAddress(bottomScreenAddr);
|
auto bottomScreen = colourBufferCache.findFromAddress(bottomScreenAddr);
|
||||||
screenFramebuffer.bind(OpenGL::DrawFramebuffer);
|
screenFramebuffer.bind(OpenGL::DrawFramebuffer);
|
||||||
|
|
||||||
OpenGL::setClearColor(0.f);
|
gl.setClearColour(0.f, 0.f, 0.f, 1.f);
|
||||||
OpenGL::clearColor();
|
OpenGL::clearColor();
|
||||||
|
|
||||||
if (topScreen) {
|
if (topScreen) {
|
||||||
|
@ -504,8 +504,9 @@ void RendererGL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 co
|
||||||
const float b = getBits<8, 8>(value) / 255.0f;
|
const float b = getBits<8, 8>(value) / 255.0f;
|
||||||
const float a = (value & 0xff) / 255.0f;
|
const float a = (value & 0xff) / 255.0f;
|
||||||
color->get().fbo.bind(OpenGL::DrawFramebuffer);
|
color->get().fbo.bind(OpenGL::DrawFramebuffer);
|
||||||
|
|
||||||
gl.setColourMask(true, true, true, true);
|
gl.setColourMask(true, true, true, true);
|
||||||
OpenGL::setClearColor(r, g, b, a);
|
gl.setClearColour(r, g, b, a);
|
||||||
OpenGL::clearColor();
|
OpenGL::clearColor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue