Addressed smaller comments, fb color/depth separate

This commit is contained in:
tfarley 2015-05-16 23:46:46 -07:00
parent d517757053
commit dfc807daf9
14 changed files with 227 additions and 200 deletions

View File

@ -355,7 +355,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
// GX request DMA - typically used for copying memory from GSP heap to VRAM // GX request DMA - typically used for copying memory from GSP heap to VRAM
case CommandId::REQUEST_DMA: case CommandId::REQUEST_DMA:
VideoCore::g_renderer->hw_rasterizer->NotifyPreCopy(Memory::VirtualToPhysicalAddress(command.dma_request.source_address), VideoCore::g_renderer->hw_rasterizer->NotifyPreRead(Memory::VirtualToPhysicalAddress(command.dma_request.source_address),
command.dma_request.size); command.dma_request.size);
memcpy(Memory::GetPointer(command.dma_request.dest_address), memcpy(Memory::GetPointer(command.dma_request.dest_address),

View File

@ -131,10 +131,10 @@ inline void Write(u32 addr, const T data) {
u32 output_width = config.output_width / horizontal_scale; u32 output_width = config.output_width / horizontal_scale;
u32 output_height = config.output_height / vertical_scale; u32 output_height = config.output_height / vertical_scale;
u32 input_size = config.input_height.Value() * config.input_width.Value() * GPU::Regs::BytesPerPixel(config.input_format.Value()); u32 input_size = config.input_height * config.input_width * GPU::Regs::BytesPerPixel(config.input_format);
u32 output_size = output_height * output_width * GPU::Regs::BytesPerPixel(config.output_format.Value()); u32 output_size = output_height * output_width * GPU::Regs::BytesPerPixel(config.output_format);
VideoCore::g_renderer->hw_rasterizer->NotifyPreCopy(config.GetPhysicalInputAddress(), input_size); VideoCore::g_renderer->hw_rasterizer->NotifyPreRead(config.GetPhysicalInputAddress(), input_size);
if (config.raw_copy) { if (config.raw_copy) {
// Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions

View File

@ -15,10 +15,7 @@ public:
/// Initialize API-specific GPU objects /// Initialize API-specific GPU objects
virtual void InitObjects() = 0; virtual void InitObjects() = 0;
/// Set the window (context) to draw with /// Queues the primitive formed by the given vertices for rendering
virtual void SetWindow(EmuWindow* window) = 0;
/// Converts the triangle verts to hardware data format and adds them to the current batch
virtual void AddTriangle(const Pica::VertexShader::OutputVertex& v0, virtual void AddTriangle(const Pica::VertexShader::OutputVertex& v0,
const Pica::VertexShader::OutputVertex& v1, const Pica::VertexShader::OutputVertex& v1,
const Pica::VertexShader::OutputVertex& v2) = 0; const Pica::VertexShader::OutputVertex& v2) = 0;
@ -26,9 +23,9 @@ public:
/// Draw the current batch of triangles /// Draw the current batch of triangles
virtual void DrawTriangles() = 0; virtual void DrawTriangles() = 0;
/// Notify rasterizer that a copy within 3DS memory will occur after this notification /// Notify rasterizer that the specified 3DS memory region will be read from after this notification
virtual void NotifyPreCopy(u32 src_paddr, u32 size) = 0; virtual void NotifyPreRead(u32 paddr, u32 size) = 0;
/// Notify rasterizer that a 3DS memory region has been changed /// Notify rasterizer that a 3DS memory region has been changed
virtual void NotifyFlush(u32 paddr, u32 size) = 0; virtual void NotifyFlush(u32 addr, u32 size) = 0;
}; };

View File

@ -500,6 +500,23 @@ struct Regs {
RGBA4 = 4, RGBA4 = 4,
}; };
// Returns the number of bytes in the specified color format
static unsigned BytesPerColorPixel(u32 format) {
switch (format) {
case ColorFormat::RGBA8:
return 4;
case ColorFormat::RGB8:
return 3;
case ColorFormat::RGB5A1:
case ColorFormat::RGB565:
case ColorFormat::RGBA4:
return 2;
default:
LOG_CRITICAL(HW_GPU, "Unknown color format %u", format);
UNIMPLEMENTED();
}
}
INSERT_PADDING_WORDS(0x6); INSERT_PADDING_WORDS(0x6);
DepthFormat depth_format; DepthFormat depth_format;

View File

@ -12,83 +12,86 @@
namespace PicaToGL { namespace PicaToGL {
static GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
switch (mode) { static const GLenum wrap_mode_table[] = {
case Pica::Regs::TextureConfig::WrapMode::ClampToEdge: GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
0, // Unknown
GL_REPEAT, // WrapMode::Repeat
GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat
};
// Range check table for input
if (mode >= sizeof(wrap_mode_table) / sizeof(GLenum)) {
LOG_CRITICAL(Render_OpenGL, "Unknown texture wrap mode %d", mode);
UNREACHABLE();
return GL_CLAMP_TO_EDGE; return GL_CLAMP_TO_EDGE;
case Pica::Regs::TextureConfig::WrapMode::Repeat: }
return GL_REPEAT;
case Pica::Regs::TextureConfig::WrapMode::MirroredRepeat: GLenum gl_mode = wrap_mode_table[mode];
return GL_MIRRORED_REPEAT;
default: // Check for dummy values indicating an unknown mode
if (gl_mode == 0) {
LOG_CRITICAL(Render_OpenGL, "Unknown texture wrap mode %d", mode); LOG_CRITICAL(Render_OpenGL, "Unknown texture wrap mode %d", mode);
UNIMPLEMENTED(); UNIMPLEMENTED();
return GL_CLAMP_TO_EDGE; return GL_CLAMP_TO_EDGE;
} }
return gl_mode;
} }
static GLenum BlendFunc(u32 factor) { inline GLenum BlendFunc(u32 factor) {
switch (factor) { static const GLenum blend_func_table[] = {
case Pica::registers.output_merger.alpha_blending.Zero: GL_ZERO, // BlendFactor::Zero
return GL_ZERO; GL_ONE, // BlendFactor::One
case Pica::registers.output_merger.alpha_blending.One: GL_SRC_COLOR, // BlendFactor::SourceColor
return GL_ONE; GL_ONE_MINUS_SRC_COLOR, // BlendFactor::OneMinusSourceColor
case Pica::registers.output_merger.alpha_blending.SourceColor: GL_DST_COLOR, // BlendFactor::DestColor
return GL_SRC_COLOR; GL_ONE_MINUS_DST_COLOR, // BlendFactor::OneMinusDestColor
case Pica::registers.output_merger.alpha_blending.OneMinusSourceColor: GL_SRC_ALPHA, // BlendFactor::SourceAlpha
return GL_ONE_MINUS_SRC_COLOR; GL_ONE_MINUS_SRC_ALPHA, // BlendFactor::OneMinusSourceAlpha
case Pica::registers.output_merger.alpha_blending.DestColor: GL_DST_ALPHA, // BlendFactor::DestAlpha
return GL_DST_COLOR; GL_ONE_MINUS_DST_ALPHA, // BlendFactor::OneMinusDestAlpha
case Pica::registers.output_merger.alpha_blending.OneMinusDestColor: GL_CONSTANT_COLOR, // BlendFactor::ConstantColor
return GL_ONE_MINUS_DST_COLOR; GL_ONE_MINUS_CONSTANT_COLOR, // BlendFactor::OneMinusConstantColor
case Pica::registers.output_merger.alpha_blending.SourceAlpha: GL_CONSTANT_ALPHA, // BlendFactor::ConstantAlpha
return GL_SRC_ALPHA; GL_ONE_MINUS_CONSTANT_ALPHA, // BlendFactor::OneMinusConstantAlpha
case Pica::registers.output_merger.alpha_blending.OneMinusSourceAlpha: GL_SRC_ALPHA_SATURATE, // BlendFactor::SourceAlphaSaturate
return GL_ONE_MINUS_SRC_ALPHA; };
case Pica::registers.output_merger.alpha_blending.DestAlpha:
return GL_DST_ALPHA; // Range check table for input
case Pica::registers.output_merger.alpha_blending.OneMinusDestAlpha: if (factor >= sizeof(blend_func_table) / sizeof(GLenum)) {
return GL_ONE_MINUS_DST_ALPHA;
case Pica::registers.output_merger.alpha_blending.ConstantColor:
return GL_CONSTANT_COLOR;
case Pica::registers.output_merger.alpha_blending.OneMinusConstantColor:
return GL_ONE_MINUS_CONSTANT_COLOR;
case Pica::registers.output_merger.alpha_blending.ConstantAlpha:
return GL_CONSTANT_ALPHA;
case Pica::registers.output_merger.alpha_blending.OneMinusConstantAlpha:
return GL_ONE_MINUS_CONSTANT_ALPHA;
case Pica::registers.output_merger.alpha_blending.SourceAlphaSaturate:
return GL_SRC_ALPHA_SATURATE;
default:
LOG_CRITICAL(Render_OpenGL, "Unknown blend factor %d", factor); LOG_CRITICAL(Render_OpenGL, "Unknown blend factor %d", factor);
UNIMPLEMENTED(); UNREACHABLE();
return GL_ONE; return GL_ONE;
} }
return blend_func_table[factor];
} }
static GLenum CompareFunc(u32 func) { inline GLenum CompareFunc(u32 func) {
switch (func) { static const GLenum compare_func_table[] = {
case Pica::registers.output_merger.Never: GL_NEVER, // CompareFunc::Never
return GL_NEVER; GL_ALWAYS, // CompareFunc::Always
case Pica::registers.output_merger.Always: GL_EQUAL, // CompareFunc::Equal
return GL_ALWAYS; GL_NOTEQUAL, // CompareFunc::NotEqual
case Pica::registers.output_merger.Equal: GL_LESS, // CompareFunc::LessThan
return GL_EQUAL; GL_LEQUAL, // CompareFunc::LessThanOrEqual
case Pica::registers.output_merger.NotEqual: GL_GREATER, // CompareFunc::GreaterThan
return GL_NOTEQUAL; GL_GEQUAL, // CompareFunc::GreaterThanOrEqual
case Pica::registers.output_merger.LessThan: };
return GL_LESS;
case Pica::registers.output_merger.LessThanOrEqual: // Range check table for input
return GL_LEQUAL; if (func >= sizeof(compare_func_table) / sizeof(GLenum)) {
case Pica::registers.output_merger.GreaterThan:
return GL_GREATER;
case Pica::registers.output_merger.GreaterThanOrEqual:
return GL_GEQUAL;
default:
LOG_CRITICAL(Render_OpenGL, "Unknown compare function %d", func); LOG_CRITICAL(Render_OpenGL, "Unknown compare function %d", func);
UNIMPLEMENTED(); UNREACHABLE();
return GL_ALWAYS; return GL_ALWAYS;
} }
return compare_func_table[func];
} }
} // namespace } // namespace

View File

@ -17,32 +17,12 @@
#include <memory> #include <memory>
u32 ColorFormatBytesPerPixel(u32 format) {
switch (format) {
case Pica::registers.framebuffer.RGBA8:
return 4;
case Pica::registers.framebuffer.RGB8:
return 3;
case Pica::registers.framebuffer.RGB5A1:
case Pica::registers.framebuffer.RGB565:
case Pica::registers.framebuffer.RGBA4:
return 2;
default:
LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer color format %x", format);
UNIMPLEMENTED();
break;
}
return 0;
}
RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr(0) { RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr(0) {
} }
RasterizerOpenGL::~RasterizerOpenGL() { RasterizerOpenGL::~RasterizerOpenGL() {
// Set context for automatic resource destruction
render_window->MakeCurrent();
} }
void RasterizerOpenGL::InitObjects() { void RasterizerOpenGL::InitObjects() {
@ -109,7 +89,7 @@ void RasterizerOpenGL::InitObjects() {
// Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation
fb_color_texture.texture.Create(); fb_color_texture.texture.Create();
ReconfigColorTexture(fb_color_texture, Pica::registers.framebuffer.RGBA8, 1, 1); ReconfigureColorTexture(fb_color_texture, Pica::registers.framebuffer.RGBA8, 1, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -117,7 +97,7 @@ void RasterizerOpenGL::InitObjects() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
fb_depth_texture.texture.Create(); fb_depth_texture.texture.Create();
ReconfigDepthTexture(fb_depth_texture, Pica::Regs::DepthFormat::D16, 1, 1); ReconfigureDepthTexture(fb_depth_texture, Pica::Regs::DepthFormat::D16, 1, 1);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -138,13 +118,8 @@ void RasterizerOpenGL::InitObjects() {
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_color_texture.texture.GetHandle(), 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_color_texture.texture.GetHandle(), 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.GetHandle(), 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.GetHandle(), 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { ASSERT_MSG(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE,
LOG_CRITICAL(Render_OpenGL, "Framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER)); "OpenGL rasterizer framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER));
}
}
void RasterizerOpenGL::SetWindow(EmuWindow* window) {
render_window = window;
} }
void RasterizerOpenGL::AddTriangle(const Pica::VertexShader::OutputVertex& v0, void RasterizerOpenGL::AddTriangle(const Pica::VertexShader::OutputVertex& v0,
@ -156,8 +131,6 @@ void RasterizerOpenGL::AddTriangle(const Pica::VertexShader::OutputVertex& v0,
} }
void RasterizerOpenGL::DrawTriangles() { void RasterizerOpenGL::DrawTriangles() {
render_window->MakeCurrent();
state.Apply(); state.Apply();
SyncFramebuffer(); SyncFramebuffer();
@ -169,16 +142,14 @@ void RasterizerOpenGL::DrawTriangles() {
vertex_batch.clear(); vertex_batch.clear();
} }
void RasterizerOpenGL::NotifyPreCopy(PAddr src_addr, u32 size) { void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) {
if (!Settings::values.use_hw_renderer) if (!Settings::values.use_hw_renderer)
return; return;
render_window->MakeCurrent();
state.Apply(); state.Apply();
PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress();
u32 cur_fb_color_size = ColorFormatBytesPerPixel(Pica::registers.framebuffer.color_format) u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format)
* Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight();
PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress();
@ -186,18 +157,18 @@ void RasterizerOpenGL::NotifyPreCopy(PAddr src_addr, u32 size) {
* Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight();
// If source memory region overlaps 3DS framebuffers, commit them before the copy happens // If source memory region overlaps 3DS framebuffers, commit them before the copy happens
PAddr max_low_addr_bound = std::max(src_addr, cur_fb_color_addr); PAddr max_low_addr_bound = std::max(addr, cur_fb_color_addr);
PAddr min_hi_addr_bound = std::min(src_addr + size, cur_fb_color_addr + cur_fb_color_size); PAddr min_hi_addr_bound = std::min(addr + size, cur_fb_color_addr + cur_fb_color_size);
if (max_low_addr_bound <= min_hi_addr_bound) { if (max_low_addr_bound <= min_hi_addr_bound) {
CommitFramebuffer(); CommitColorBuffer();
} }
max_low_addr_bound = std::max(src_addr, cur_fb_depth_addr); max_low_addr_bound = std::max(addr, cur_fb_depth_addr);
min_hi_addr_bound = std::min(src_addr + size, cur_fb_depth_addr + cur_fb_depth_size); min_hi_addr_bound = std::min(addr + size, cur_fb_depth_addr + cur_fb_depth_size);
if (max_low_addr_bound <= min_hi_addr_bound) { if (max_low_addr_bound <= min_hi_addr_bound) {
CommitFramebuffer(); CommitDepthBuffer();
} }
} }
@ -205,12 +176,10 @@ void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) {
if (!Settings::values.use_hw_renderer) if (!Settings::values.use_hw_renderer)
return; return;
render_window->MakeCurrent();
state.Apply(); state.Apply();
PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress();
u32 cur_fb_color_size = ColorFormatBytesPerPixel(Pica::registers.framebuffer.color_format) u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format)
* Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight();
PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress();
@ -236,7 +205,7 @@ void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) {
res_cache.NotifyFlush(addr, size); res_cache.NotifyFlush(addr, size);
} }
void RasterizerOpenGL::ReconfigColorTexture(TextureInfo& texture, u32 format, u32 width, u32 height) { void RasterizerOpenGL::ReconfigureColorTexture(TextureInfo& texture, u32 format, u32 width, u32 height) {
GLint internal_format; GLint internal_format;
texture.format = format; texture.format = format;
@ -293,7 +262,7 @@ void RasterizerOpenGL::ReconfigColorTexture(TextureInfo& texture, u32 format, u3
texture.gl_format, texture.gl_type, nullptr); texture.gl_format, texture.gl_type, nullptr);
} }
void RasterizerOpenGL::ReconfigDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) { void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) {
GLint internal_format; GLint internal_format;
texture.format = format; texture.format = format;
@ -351,15 +320,16 @@ void RasterizerOpenGL::SyncFramebuffer() {
// Commit if fb modified in any way // Commit if fb modified in any way
if (fb_modified) { if (fb_modified) {
CommitFramebuffer(); CommitColorBuffer();
CommitDepthBuffer();
} }
// Reconfigure framebuffer textures if any property has changed // Reconfigure framebuffer textures if any property has changed
if (fb_prop_changed) { if (fb_prop_changed) {
ReconfigColorTexture(fb_color_texture, new_fb_color_format, ReconfigureColorTexture(fb_color_texture, new_fb_color_format,
Pica::registers.framebuffer.GetWidth(), Pica::registers.framebuffer.GetHeight()); Pica::registers.framebuffer.GetWidth(), Pica::registers.framebuffer.GetHeight());
ReconfigDepthTexture(fb_depth_texture, new_fb_depth_format, ReconfigureDepthTexture(fb_depth_texture, new_fb_depth_format,
Pica::registers.framebuffer.GetWidth(), Pica::registers.framebuffer.GetHeight()); Pica::registers.framebuffer.GetWidth(), Pica::registers.framebuffer.GetHeight());
// Only attach depth buffer as stencil if it supports stencil // Only attach depth buffer as stencil if it supports stencil
@ -385,10 +355,6 @@ void RasterizerOpenGL::SyncFramebuffer() {
last_fb_color_addr = cur_fb_color_addr; last_fb_color_addr = cur_fb_color_addr;
last_fb_depth_addr = cur_fb_depth_addr; last_fb_depth_addr = cur_fb_depth_addr;
// Currently not needed b/c of reloading buffers below, but will be needed for high-res rendering
//glDepthMask(GL_TRUE);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ReloadColorBuffer(); ReloadColorBuffer();
ReloadDepthBuffer(); ReloadDepthBuffer();
} }
@ -549,7 +515,7 @@ void RasterizerOpenGL::ReloadColorBuffer() {
if (color_buffer == nullptr) if (color_buffer == nullptr)
return; return;
u32 bytes_per_pixel = ColorFormatBytesPerPixel(fb_color_texture.format); u32 bytes_per_pixel = Pica::registers.framebuffer.BytesPerColorPixel(fb_color_texture.format);
std::unique_ptr<u8[]> temp_fb_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]); std::unique_ptr<u8[]> temp_fb_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]);
@ -626,12 +592,12 @@ void RasterizerOpenGL::ReloadDepthBuffer() {
fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_fb_depth_buffer.get()); fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_fb_depth_buffer.get());
} }
void RasterizerOpenGL::CommitFramebuffer() { void RasterizerOpenGL::CommitColorBuffer() {
if (last_fb_color_addr != 0) { if (last_fb_color_addr != 0) {
u8* color_buffer = Memory::GetPhysicalPointer(last_fb_color_addr); u8* color_buffer = Memory::GetPhysicalPointer(last_fb_color_addr);
if (color_buffer != nullptr) { if (color_buffer != nullptr) {
u32 bytes_per_pixel = ColorFormatBytesPerPixel(fb_color_texture.format); u32 bytes_per_pixel = Pica::registers.framebuffer.BytesPerColorPixel(fb_color_texture.format);
std::unique_ptr<u8[]> temp_gl_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]); std::unique_ptr<u8[]> temp_gl_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]);
@ -656,7 +622,9 @@ void RasterizerOpenGL::CommitFramebuffer() {
} }
} }
} }
}
void RasterizerOpenGL::CommitDepthBuffer() {
if (last_fb_depth_addr != 0) { if (last_fb_depth_addr != 0) {
// TODO: Output seems correct visually, but doesn't quite match sw renderer output. One of them is wrong. // TODO: Output seems correct visually, but doesn't quite match sw renderer output. One of them is wrong.
u8* depth_buffer = Memory::GetPhysicalPointer(last_fb_depth_addr); u8* depth_buffer = Memory::GetPhysicalPointer(last_fb_depth_addr);

View File

@ -18,10 +18,7 @@ public:
/// Initialize API-specific GPU objects /// Initialize API-specific GPU objects
void InitObjects() override; void InitObjects() override;
/// Set the window (context) to draw with /// Queues the primitive formed by the given vertices for rendering
void SetWindow(EmuWindow* window) override;
/// Converts the triangle verts to hardware data format and adds them to the current batch
void AddTriangle(const Pica::VertexShader::OutputVertex& v0, void AddTriangle(const Pica::VertexShader::OutputVertex& v0,
const Pica::VertexShader::OutputVertex& v1, const Pica::VertexShader::OutputVertex& v1,
const Pica::VertexShader::OutputVertex& v2) override; const Pica::VertexShader::OutputVertex& v2) override;
@ -29,8 +26,8 @@ public:
/// Draw the current batch of triangles /// Draw the current batch of triangles
void DrawTriangles() override; void DrawTriangles() override;
/// Notify rasterizer that a copy within 3DS memory will occur after this notification /// Notify rasterizer that the specified 3DS memory region will be read from after this notification
void NotifyPreCopy(PAddr src_addr, u32 size) override; void NotifyPreRead(PAddr addr, u32 size) override;
/// Notify rasterizer that a 3DS memory region has been changed /// Notify rasterizer that a 3DS memory region has been changed
void NotifyFlush(PAddr addr, u32 size) override; void NotifyFlush(PAddr addr, u32 size) override;
@ -95,10 +92,10 @@ private:
}; };
/// Reconfigure the OpenGL color texture to use the given format and dimensions /// Reconfigure the OpenGL color texture to use the given format and dimensions
void ReconfigColorTexture(TextureInfo& texture, u32 format, u32 width, u32 height); void ReconfigureColorTexture(TextureInfo& texture, u32 format, u32 width, u32 height);
/// Reconfigure the OpenGL depth texture to use the given format and dimensions /// Reconfigure the OpenGL depth texture to use the given format and dimensions
void ReconfigDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height);
/// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer
void SyncFramebuffer(); void SyncFramebuffer();
@ -113,13 +110,19 @@ private:
void ReloadDepthBuffer(); void ReloadDepthBuffer();
/** /**
* Save the current OpenGL framebuffer to the current PICA framebuffer in 3ds memory * Save the current OpenGL color framebuffer to the current PICA framebuffer in 3ds memory
* Loads the OpenGL framebuffer textures into temporary buffers * Loads the OpenGL framebuffer textures into temporary buffers
* Then copies into the 3ds framebuffer using proper Morton order * Then copies into the 3ds framebuffer using proper Morton order
*/ */
void CommitFramebuffer(); void CommitColorBuffer();
/**
* Save the current OpenGL depth framebuffer to the current PICA framebuffer in 3ds memory
* Loads the OpenGL framebuffer textures into temporary buffers
* Then copies into the 3ds framebuffer using proper Morton order
*/
void CommitDepthBuffer();
EmuWindow* render_window;
RasterizerCacheOpenGL res_cache; RasterizerCacheOpenGL res_cache;
std::vector<HardwareVertex> vertex_batch; std::vector<HardwareVertex> vertex_batch;

View File

@ -2,7 +2,10 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/make_unique.h"
#include "core/memory.h" #include "core/memory.h"
#include "video_core/renderer_opengl/gl_pica_to_gl.h" #include "video_core/renderer_opengl/gl_pica_to_gl.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h" #include "video_core/renderer_opengl/gl_rasterizer_cache.h"
#include "video_core/debug_utils/debug_utils.h" #include "video_core/debug_utils/debug_utils.h"
@ -21,7 +24,7 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, int texture_u
state.texture_units[texture_unit].texture_2d = cached_texture->second->texture.GetHandle(); state.texture_units[texture_unit].texture_2d = cached_texture->second->texture.GetHandle();
state.Apply(); state.Apply();
} else { } else {
std::unique_ptr<CachedTexture> new_texture(new CachedTexture()); std::unique_ptr<CachedTexture> new_texture = Common::make_unique<CachedTexture>();
new_texture->texture.Create(); new_texture->texture.Create();
state.texture_units[texture_unit].texture_2d = new_texture->texture.GetHandle(); state.texture_units[texture_unit].texture_2d = new_texture->texture.GetHandle();
@ -31,8 +34,8 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, int texture_u
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(config.config.wrap_s.Value())); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(config.config.wrap_s));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(config.config.wrap_t.Value())); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(config.config.wrap_t));
const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format);
@ -40,11 +43,12 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, int texture_u
new_texture->height = info.height; new_texture->height = info.height;
new_texture->size = info.width * info.height * Pica::Regs::NibblesPerPixel(info.format); new_texture->size = info.width * info.height * Pica::Regs::NibblesPerPixel(info.format);
u8* texture_src_data = Memory::GetPhysicalPointer(texture_addr);
std::unique_ptr<Math::Vec4<u8>[]> temp_texture_buffer_rgba(new Math::Vec4<u8>[info.width * info.height]); std::unique_ptr<Math::Vec4<u8>[]> temp_texture_buffer_rgba(new Math::Vec4<u8>[info.width * info.height]);
for (int y = 0; y < info.height; ++y) { for (int y = 0; y < info.height; ++y) {
for (int x = 0; x < info.width; ++x) { for (int x = 0; x < info.width; ++x) {
temp_texture_buffer_rgba[x + info.width * y] = Pica::DebugUtils::LookupTexture(Memory::GetPhysicalPointer(texture_addr), x, info.height - 1 - y, info); temp_texture_buffer_rgba[x + info.width * y] = Pica::DebugUtils::LookupTexture(texture_src_data, x, info.height - 1 - y, info);
} }
} }
@ -56,7 +60,7 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, int texture_u
void RasterizerCacheOpenGL::NotifyFlush(PAddr addr, u32 size) { void RasterizerCacheOpenGL::NotifyFlush(PAddr addr, u32 size) {
// Flush any texture that falls in the flushed region // Flush any texture that falls in the flushed region
for (auto it = texture_cache.begin(); it != texture_cache.end();) { for (auto it = texture_cache.begin(); it != texture_cache.upper_bound(addr + size);) {
PAddr max_low_addr_bound = std::max(addr, it->first); PAddr max_low_addr_bound = std::max(addr, it->first);
PAddr min_hi_addr_bound = std::min(addr + size, it->first + it->second->size); PAddr min_hi_addr_bound = std::min(addr + size, it->first + it->second->size);

View File

@ -5,20 +5,11 @@
#include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_resource_manager.h"
#include "video_core/renderer_opengl/gl_shader_util.h" #include "video_core/renderer_opengl/gl_shader_util.h"
// OGLResource base class
OGLResource::OGLResource() : handle(0) {
}
OGLResource::~OGLResource() {
}
void OGLResource::Release() {
}
// Textures // Textures
OGLTexture::OGLTexture() : handle(0) {
}
OGLTexture::~OGLTexture() { OGLTexture::~OGLTexture() {
Release(); Release();
} }
@ -37,6 +28,10 @@ void OGLTexture::Release() {
} }
// Shaders // Shaders
OGLShader::OGLShader() : handle(0) {
}
OGLShader::~OGLShader() { OGLShader::~OGLShader() {
Release(); Release();
} }
@ -55,6 +50,10 @@ void OGLShader::Release() {
} }
// Buffer objects // Buffer objects
OGLBuffer::OGLBuffer() : handle(0) {
}
OGLBuffer::~OGLBuffer() { OGLBuffer::~OGLBuffer() {
Release(); Release();
} }
@ -73,6 +72,10 @@ void OGLBuffer::Release() {
} }
// Vertex array objects // Vertex array objects
OGLVertexArray::OGLVertexArray() : handle(0) {
}
OGLVertexArray::~OGLVertexArray() { OGLVertexArray::~OGLVertexArray() {
Release(); Release();
} }
@ -91,6 +94,10 @@ void OGLVertexArray::Release() {
} }
// Framebuffers // Framebuffers
OGLFramebuffer::OGLFramebuffer() : handle(0) {
}
OGLFramebuffer::~OGLFramebuffer() { OGLFramebuffer::~OGLFramebuffer() {
Release(); Release();
} }

View File

@ -8,74 +8,102 @@
#include "generated/gl_3_2_core.h" #include "generated/gl_3_2_core.h"
class OGLResource : NonCopyable { class OGLTexture : public NonCopyable {
public: public:
OGLResource(); OGLTexture();
virtual ~OGLResource(); ~OGLTexture();
/// Returns the internal OpenGL resource handle for this resource /// Returns the internal OpenGL resource handle for this resource
inline GLuint GetHandle() { inline GLuint GetHandle() {
return handle; return handle;
} }
/// Creates a new internal OpenGL resource and stores the handle
void Create();
/// Deletes the internal OpenGL resource /// Deletes the internal OpenGL resource
virtual void Release(); void Release();
protected: protected:
GLuint handle; GLuint handle;
}; };
class OGLTexture : public OGLResource { class OGLShader : public NonCopyable {
public: public:
~OGLTexture() override; OGLShader();
~OGLShader();
/// Creates a new internal OpenGL resource and stores the handle /// Returns the internal OpenGL resource handle for this resource
void Create(); inline GLuint GetHandle() {
return handle;
/// Deletes the internal OpenGL resource }
void Release() override;
};
class OGLShader : public OGLResource {
public:
~OGLShader() override;
/// Creates a new internal OpenGL resource and stores the handle /// Creates a new internal OpenGL resource and stores the handle
void Create(const char* vert_shader, const char* frag_shader); void Create(const char* vert_shader, const char* frag_shader);
/// Deletes the internal OpenGL resource /// Deletes the internal OpenGL resource
void Release() override; void Release();
protected:
GLuint handle;
}; };
class OGLBuffer : public OGLResource { class OGLBuffer : public NonCopyable {
public: public:
~OGLBuffer() override; OGLBuffer();
~OGLBuffer();
/// Returns the internal OpenGL resource handle for this resource
inline GLuint GetHandle() {
return handle;
}
/// Creates a new internal OpenGL resource and stores the handle /// Creates a new internal OpenGL resource and stores the handle
void Create(); void Create();
/// Deletes the internal OpenGL resource /// Deletes the internal OpenGL resource
void Release() override; void Release();
protected:
GLuint handle;
}; };
class OGLVertexArray : public OGLResource { class OGLVertexArray : public NonCopyable {
public: public:
~OGLVertexArray() override; OGLVertexArray();
~OGLVertexArray();
/// Returns the internal OpenGL resource handle for this resource
inline GLuint GetHandle() {
return handle;
}
/// Creates a new internal OpenGL resource and stores the handle /// Creates a new internal OpenGL resource and stores the handle
void Create(); void Create();
/// Deletes the internal OpenGL resource /// Deletes the internal OpenGL resource
void Release() override; void Release();
protected:
GLuint handle;
}; };
class OGLFramebuffer : public OGLResource { class OGLFramebuffer : public NonCopyable {
public: public:
~OGLFramebuffer() override; OGLFramebuffer();
~OGLFramebuffer();
/// Returns the internal OpenGL resource handle for this resource
inline GLuint GetHandle() {
return handle;
}
/// Creates a new internal OpenGL resource and stores the handle /// Creates a new internal OpenGL resource and stores the handle
void Create(); void Create();
/// Deletes the internal OpenGL resource /// Deletes the internal OpenGL resource
void Release() override; void Release();
protected:
GLuint handle;
}; };

View File

@ -191,33 +191,33 @@ vec4 GetSource(int source) {
return g_last_tex_env_out; return g_last_tex_env_out;
} }
return vec4(0.0, 0.0, 0.0, 0.0); return vec4(0.0);
} }
vec3 GetColorModifier(int factor, vec4 color) { vec3 GetColorModifier(int factor, vec4 color) {
if (factor == COLORMODIFIER_SOURCECOLOR) { if (factor == COLORMODIFIER_SOURCECOLOR) {
return color.rgb; return color.rgb;
} else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) { } else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) {
return vec3(1.0, 1.0, 1.0) - color.rgb; return vec3(1.0) - color.rgb;
} else if (factor == COLORMODIFIER_SOURCEALPHA) { } else if (factor == COLORMODIFIER_SOURCEALPHA) {
return color.aaa; return color.aaa;
} else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) { } else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) {
return vec3(1.0, 1.0, 1.0) - color.aaa; return vec3(1.0) - color.aaa;
} else if (factor == COLORMODIFIER_SOURCERED) { } else if (factor == COLORMODIFIER_SOURCERED) {
return color.rrr; return color.rrr;
} else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) { } else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) {
return vec3(1.0, 1.0, 1.0) - color.rrr; return vec3(1.0) - color.rrr;
} else if (factor == COLORMODIFIER_SOURCEGREEN) { } else if (factor == COLORMODIFIER_SOURCEGREEN) {
return color.ggg; return color.ggg;
} else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) { } else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) {
return vec3(1.0, 1.0, 1.0) - color.ggg; return vec3(1.0) - color.ggg;
} else if (factor == COLORMODIFIER_SOURCEBLUE) { } else if (factor == COLORMODIFIER_SOURCEBLUE) {
return color.bbb; return color.bbb;
} else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) { } else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) {
return vec3(1.0, 1.0, 1.0) - color.bbb; return vec3(1.0) - color.bbb;
} }
return vec3(0.0, 0.0, 0.0); return vec3(0.0);
} }
float GetAlphaModifier(int factor, vec4 color) { float GetAlphaModifier(int factor, vec4 color) {
@ -250,9 +250,9 @@ vec3 ColorCombine(int op, vec3 color[3]) {
} else if (op == OPERATION_ADD) { } else if (op == OPERATION_ADD) {
return min(color[0] + color[1], 1.0); return min(color[0] + color[1], 1.0);
} else if (op == OPERATION_ADDSIGNED) { } else if (op == OPERATION_ADDSIGNED) {
return clamp(color[0] + color[1] - vec3(0.5, 0.5, 0.5), 0.0, 1.0); return clamp(color[0] + color[1] - vec3(0.5), 0.0, 1.0);
} else if (op == OPERATION_LERP) { } else if (op == OPERATION_LERP) {
return color[0] * color[2] + color[1] * (vec3(1.0, 1.0, 1.0) - color[2]); return color[0] * color[2] + color[1] * (vec3(1.0) - color[2]);
} else if (op == OPERATION_SUBTRACT) { } else if (op == OPERATION_SUBTRACT) {
return max(color[0] - color[1], 0.0); return max(color[0] - color[1], 0.0);
} else if (op == OPERATION_MULTIPLYTHENADD) { } else if (op == OPERATION_MULTIPLYTHENADD) {
@ -261,7 +261,7 @@ vec3 ColorCombine(int op, vec3 color[3]) {
return min(color[0] + color[1], 1.0) * color[2]; return min(color[0] + color[1], 1.0) * color[2];
} }
return vec3(0.0, 0.0, 0.0); return vec3(0.0);
} }
float AlphaCombine(int op, float alpha[3]) { float AlphaCombine(int op, float alpha[3]) {

View File

@ -42,7 +42,7 @@ OpenGLState::OpenGLState() {
draw.shader_program = 0; draw.shader_program = 0;
} }
void OpenGLState::Apply() { const void OpenGLState::Apply() {
// Culling // Culling
if (cull.enabled) { if (cull.enabled) {
if (cull.enabled != cur_state.cull.enabled) { if (cull.enabled != cur_state.cull.enabled) {

View File

@ -42,6 +42,7 @@ public:
} color; // GL_BLEND_COLOR } color; // GL_BLEND_COLOR
} blend; } blend;
// 3 texture units - one for each that is used in PICA fragment shader emulation
struct { struct {
bool enabled_2d; // GL_TEXTURE_2D bool enabled_2d; // GL_TEXTURE_2D
GLuint texture_2d; // GL_TEXTURE_BINDING_2D GLuint texture_2d; // GL_TEXTURE_BINDING_2D
@ -57,12 +58,12 @@ public:
OpenGLState(); OpenGLState();
/// Get the currently active OpenGL state /// Get the currently active OpenGL state
static OpenGLState GetCurState() { static const OpenGLState& GetCurState() {
return cur_state; return cur_state;
} }
/// Apply this state as the current OpenGL state /// Apply this state as the current OpenGL state
void Apply(); const void Apply();
private: private:
static OpenGLState cur_state; static OpenGLState cur_state;

View File

@ -348,7 +348,6 @@ void RendererOpenGL::UpdateFramerate() {
*/ */
void RendererOpenGL::SetWindow(EmuWindow* window) { void RendererOpenGL::SetWindow(EmuWindow* window) {
render_window = window; render_window = window;
hw_rasterizer->SetWindow(window);
} }
/// Initialize the renderer /// Initialize the renderer