mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-11 08:39:48 +12:00
gpu: Add display transfer rectangles
This commit is contained in:
parent
f75a23b5a9
commit
c805504f70
5 changed files with 109 additions and 88 deletions
80
include/math_util.hpp
Normal file
80
include/math_util.hpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#pragma once
|
||||
#include <array>
|
||||
|
||||
namespace Math {
|
||||
// Abstraction for GLSL vectors
|
||||
template <typename T, int size>
|
||||
class Vector {
|
||||
// A GLSL vector can only have 2, 3 or 4 elements
|
||||
static_assert(size == 2 || size == 3 || size == 4);
|
||||
T m_storage[size];
|
||||
|
||||
public:
|
||||
T& r() { return m_storage[0]; }
|
||||
T& g() { return m_storage[1]; }
|
||||
T& b() {
|
||||
static_assert(size >= 3, "Out of bounds OpenGL::Vector access");
|
||||
return m_storage[2];
|
||||
}
|
||||
T& a() {
|
||||
static_assert(size >= 4, "Out of bounds OpenGL::Vector access");
|
||||
return m_storage[3];
|
||||
}
|
||||
|
||||
T& x() { return r(); }
|
||||
T& y() { return g(); }
|
||||
T& z() { return b(); }
|
||||
T& w() { return a(); }
|
||||
T& operator[](size_t index) { return m_storage[index]; }
|
||||
const T& operator[](size_t index) const { return m_storage[index]; }
|
||||
|
||||
T& u() { return r(); }
|
||||
T& v() { return g(); }
|
||||
|
||||
T& s() { return r(); }
|
||||
T& t() { return g(); }
|
||||
T& p() { return b(); }
|
||||
T& q() { return a(); }
|
||||
|
||||
Vector(std::array<T, size> list) { std::copy(list.begin(), list.end(), &m_storage[0]); }
|
||||
|
||||
Vector() {}
|
||||
};
|
||||
|
||||
using vec2 = Vector<float, 2>;
|
||||
using vec3 = Vector<float, 3>;
|
||||
using vec4 = Vector<float, 4>;
|
||||
|
||||
using dvec2 = Vector<double, 2>;
|
||||
using dvec3 = Vector<double, 3>;
|
||||
using dvec4 = Vector<double, 4>;
|
||||
|
||||
using ivec2 = Vector<int, 2>;
|
||||
using ivec3 = Vector<int, 3>;
|
||||
using ivec4 = Vector<int, 4>;
|
||||
|
||||
using uvec2 = Vector<unsigned int, 2>;
|
||||
using uvec3 = Vector<unsigned int, 3>;
|
||||
using uvec4 = Vector<unsigned int, 4>;
|
||||
|
||||
// A 2D rectangle, meant to be used for stuff like scissor rects or viewport rects
|
||||
// We're never supporting 3D rectangles, because rectangles were never meant to be 3D in the first place
|
||||
template <typename T>
|
||||
struct Rectangle {
|
||||
Vector<T, 2> start;
|
||||
Vector<T, 2> end;
|
||||
|
||||
Rectangle() : start({0}), end({0}) {}
|
||||
Rectangle(T x0, T y0, T x1, T y1) : start({x0, y0}), end({x1, y1}) {}
|
||||
|
||||
T getWidth() const {
|
||||
return std::abs(end.x() - start.x());
|
||||
}
|
||||
|
||||
T getHeight() const {
|
||||
return std::abs(end.y() - start.y());
|
||||
}
|
||||
};
|
||||
|
||||
using Rect = Rectangle<unsigned int>;
|
||||
}
|
|
@ -615,83 +615,4 @@ namespace OpenGL {
|
|||
glBlendFuncSeparate(fac1, fac2, fac3, fac4);
|
||||
}
|
||||
|
||||
// Abstraction for GLSL vectors
|
||||
template <typename T, int size>
|
||||
class Vector {
|
||||
// A GLSL vector can only have 2, 3 or 4 elements
|
||||
static_assert(size == 2 || size == 3 || size == 4);
|
||||
T m_storage[size];
|
||||
|
||||
public:
|
||||
T& r() { return m_storage[0]; }
|
||||
T& g() { return m_storage[1]; }
|
||||
T& b() {
|
||||
static_assert(size >= 3, "Out of bounds OpenGL::Vector access");
|
||||
return m_storage[2];
|
||||
}
|
||||
T& a() {
|
||||
static_assert(size >= 4, "Out of bounds OpenGL::Vector access");
|
||||
return m_storage[3];
|
||||
}
|
||||
|
||||
T& x() { return r(); }
|
||||
T& y() { return g(); }
|
||||
T& z() { return b(); }
|
||||
T& w() { return a(); }
|
||||
T& operator[](size_t index) { return m_storage[index]; }
|
||||
const T& operator[](size_t index) const { return m_storage[index]; }
|
||||
|
||||
T& u() { return r(); }
|
||||
T& v() { return g(); }
|
||||
|
||||
T& s() { return r(); }
|
||||
T& t() { return g(); }
|
||||
T& p() { return b(); }
|
||||
T& q() { return a(); }
|
||||
|
||||
Vector(std::array<T, size> list) { std::copy(list.begin(), list.end(), &m_storage[0]); }
|
||||
|
||||
Vector() {}
|
||||
};
|
||||
|
||||
using vec2 = Vector<GLfloat, 2>;
|
||||
using vec3 = Vector<GLfloat, 3>;
|
||||
using vec4 = Vector<GLfloat, 4>;
|
||||
|
||||
using dvec2 = Vector<GLdouble, 2>;
|
||||
using dvec3 = Vector<GLdouble, 3>;
|
||||
using dvec4 = Vector<GLdouble, 4>;
|
||||
|
||||
using ivec2 = Vector<GLint, 2>;
|
||||
using ivec3 = Vector<GLint, 3>;
|
||||
using ivec4 = Vector<GLint, 4>;
|
||||
|
||||
using uvec2 = Vector<GLuint, 2>;
|
||||
using uvec3 = Vector<GLuint, 3>;
|
||||
using uvec4 = Vector<GLuint, 4>;
|
||||
|
||||
// A 2D rectangle, meant to be used for stuff like scissor rects or viewport rects
|
||||
// We're never supporting 3D rectangles, because rectangles were never meant to be 3D in the first place
|
||||
// x, y: Coords of the top left vertex
|
||||
// width, height: Dimensions of the rectangle. Initialized to 0 if not specified.
|
||||
template <typename T>
|
||||
struct Rectangle {
|
||||
T x, y, width, height;
|
||||
|
||||
std::pair<T, T> topLeft() const { return std::make_pair(x, y); }
|
||||
std::pair<T, T> topRight() const { return std::make_pair(x + width, y); }
|
||||
std::pair<T, T> bottomLeft() const { return std::make_pair(x, y + height); }
|
||||
std::pair<T, T> bottomRight() const { return std::make_pair(x + width, y + height); }
|
||||
|
||||
Rectangle() : x(0), y(0), width(0), height(0) {}
|
||||
Rectangle(T x, T y, T width, T height) : x(x), y(y), width(width), height(height) {}
|
||||
|
||||
bool isEmpty() const { return width == 0 && height == 0; }
|
||||
bool isLine() const { return (width == 0 && height != 0) || (width != 0 && height == 0); }
|
||||
|
||||
void setEmpty() { x = y = width = height = 0; }
|
||||
};
|
||||
|
||||
using Rect = Rectangle<GLuint>;
|
||||
|
||||
} // end namespace OpenGL
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "PICA/regs.hpp"
|
||||
#include "boost/icl/interval.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "math_util.hpp"
|
||||
#include "opengl.hpp"
|
||||
|
||||
template <typename T>
|
||||
|
@ -10,7 +11,7 @@ using Interval = boost::icl::right_open_interval<T>;
|
|||
struct ColourBuffer {
|
||||
u32 location;
|
||||
PICA::ColorFmt format;
|
||||
OpenGL::uvec2 size;
|
||||
Math::uvec2 size;
|
||||
bool valid;
|
||||
|
||||
// Range of VRAM taken up by buffer
|
||||
|
@ -90,6 +91,15 @@ struct ColourBuffer {
|
|||
}
|
||||
}
|
||||
|
||||
Math::Rect getSubRect(u32 inputAddress, u32 width, u32 height) {
|
||||
// PICA textures have top-left origin while OpenGL has bottom-left origin.
|
||||
// Flip the rectangle on the x axis to account for this.
|
||||
const u32 startOffset = (inputAddress - location) / sizePerPixel(format);
|
||||
const u32 x0 = (startOffset % (size.x() * 8)) / 8;
|
||||
const u32 y0 = (startOffset / (size.x() * 8)) * 8;
|
||||
return Math::Rect{x0, size.y() - y0, x0 + width, size.y() - height - y0};
|
||||
}
|
||||
|
||||
bool matches(ColourBuffer& other) {
|
||||
return location == other.location && format == other.format &&
|
||||
size.x() == other.size.x() && size.y() == other.size.y();
|
||||
|
@ -103,7 +113,7 @@ struct ColourBuffer {
|
|||
struct DepthBuffer {
|
||||
u32 location;
|
||||
PICA::DepthFmt format;
|
||||
OpenGL::uvec2 size; // Implicitly set to the size of the framebuffer
|
||||
Math::uvec2 size; // Implicitly set to the size of the framebuffer
|
||||
bool valid;
|
||||
|
||||
// Range of VRAM taken up by buffer
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "PICA/regs.hpp"
|
||||
#include "boost/icl/interval.hpp"
|
||||
#include "helpers.hpp"
|
||||
#include "math_util.hpp"
|
||||
#include "opengl.hpp"
|
||||
|
||||
template <typename T>
|
||||
|
@ -13,7 +14,7 @@ struct Texture {
|
|||
u32 location;
|
||||
u32 config; // Magnification/minification filter, wrapping configs, etc
|
||||
PICA::TextureFmt format;
|
||||
OpenGL::uvec2 size;
|
||||
Math::uvec2 size;
|
||||
bool valid;
|
||||
|
||||
// Range of VRAM taken up by buffer
|
||||
|
|
|
@ -536,7 +536,7 @@ void RendererGL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 co
|
|||
|
||||
OpenGL::Framebuffer RendererGL::getColourFBO() {
|
||||
// We construct a colour buffer object and see if our cache has any matching colour buffers in it
|
||||
// If not, we allocate a texture & FBO for our framebuffer and store it in the cache
|
||||
// If not, we allocate a texture & FBO for our framebuffer and store it in the cache
|
||||
ColourBuffer sampleBuffer(colourBufferLoc, colourBufferFormat, fbSize[0], fbSize[1]);
|
||||
auto buffer = colourBufferCache.find(sampleBuffer);
|
||||
|
||||
|
@ -598,25 +598,34 @@ void RendererGL::displayTransfer(u32 inputAddr, u32 outputAddr, u32 inputSize, u
|
|||
const PICA::Scaling scaling = static_cast<PICA::Scaling>(Helpers::getBits<24, 2>(flags));
|
||||
|
||||
u32 outputWidth = outputSize & 0xffff;
|
||||
u32 outputHeight = outputSize >> 16;
|
||||
|
||||
if (inputWidth != outputWidth) {
|
||||
Helpers::warn("Strided display transfer is not handled correctly!\n");
|
||||
}
|
||||
|
||||
auto srcFramebuffer = getColourBuffer(inputAddr, inputFormat, inputWidth, inputHeight);
|
||||
Math::Rect srcRect = srcFramebuffer.getSubRect(inputAddr, outputWidth, outputHeight);
|
||||
|
||||
// Apply scaling for the destination rectangle.
|
||||
if (scaling == PICA::Scaling::X || scaling == PICA::Scaling::XY) {
|
||||
outputWidth >>= 1;
|
||||
}
|
||||
u32 outputHeight = outputSize >> 16;
|
||||
if (scaling == PICA::Scaling::XY) {
|
||||
outputHeight >>= 1;
|
||||
}
|
||||
|
||||
// If there's a framebuffer at this address, use it. Otherwise go back to our old hack and display framebuffer 0
|
||||
// Displays are hard I really don't want to try implementing them because getting a fast solution is terrible
|
||||
auto srcFramebuffer = getColourBuffer(inputAddr, inputFormat, inputWidth, inputHeight);
|
||||
auto dstFramebuffer = getColourBuffer(outputAddr, outputFormat, outputWidth, outputHeight);
|
||||
Math::Rect dstRect = dstFramebuffer.getSubRect(outputAddr, outputWidth, outputHeight);
|
||||
|
||||
Helpers::warn("Display transfer with outputAddr %08X\n", outputAddr);
|
||||
|
||||
// Blit the framebuffers
|
||||
srcFramebuffer.fbo.bind(OpenGL::ReadFramebuffer);
|
||||
dstFramebuffer.fbo.bind(OpenGL::DrawFramebuffer);
|
||||
glBlitFramebuffer(0, 0, inputWidth, inputHeight, 0, 0, outputWidth, outputHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
glBlitFramebuffer(srcRect.start.x(), srcRect.start.y(), srcRect.end.x(), srcRect.end.y(),
|
||||
dstRect.start.x(), dstRect.start.y(), dstRect.end.x(), dstRect.end.y(),
|
||||
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
||||
}
|
||||
|
||||
ColourBuffer RendererGL::getColourBuffer(u32 addr, PICA::ColorFmt format, u32 width, u32 height) {
|
||||
|
|
Loading…
Add table
Reference in a new issue