diff --git a/src/xenia/gpu/gl4/blitter.cc b/src/xenia/gpu/gl4/blitter.cc index efd6c2add..13b3ebe3e 100644 --- a/src/xenia/gpu/gl4/blitter.cc +++ b/src/xenia/gpu/gl4/blitter.cc @@ -51,7 +51,8 @@ struct VertexData { \n\ "; const std::string vs_source = header + "\n\ -layout(location = 0) uniform vec4 src_uv_params; \n\ +layout(location = 0) uniform vec4 src_uv; \n\ +layout(location = 1) uniform vec4 dest_rect; \n\ out gl_PerVertex { \n\ vec4 gl_Position; \n\ float gl_PointSize; \n\ @@ -64,7 +65,7 @@ layout(location = 0) in VertexFetch vfetch; \n\ layout(location = 0) out VertexData vtx; \n\ void main() { \n\ gl_Position = vec4(vfetch.pos.xy * vec2(2.0, -2.0) - vec2(1.0, -1.0), 0.0, 1.0); \n\ - vtx.uv = vfetch.pos.xy * src_uv_params.zw + src_uv_params.xy; \n\ + vtx.uv = vfetch.pos.xy * src_uv.zw + src_uv.xy; \n\ } \n\ "; const std::string color_fs_source = header + @@ -207,8 +208,8 @@ struct SavedState { } }; -void Blitter::Draw(GLuint src_texture, int32_t src_x, int32_t src_y, - int32_t src_width, int32_t src_height, GLenum filter) { +void Blitter::Draw(GLuint src_texture, Rect2D src_rect, Rect2D dest_rect, + GLenum filter) { glDisable(GL_SCISSOR_TEST); glDisable(GL_STENCIL_TEST); glDisablei(GL_BLEND, 0); @@ -228,6 +229,8 @@ void Blitter::Draw(GLuint src_texture, int32_t src_x, int32_t src_y, break; } + glViewport(0, 0, dest_rect.width, dest_rect.height); + // TODO(benvanik): avoid this? GLint src_texture_width; glGetTextureLevelParameteriv(src_texture, 0, GL_TEXTURE_WIDTH, @@ -235,10 +238,12 @@ void Blitter::Draw(GLuint src_texture, int32_t src_x, int32_t src_y, GLint src_texture_height; glGetTextureLevelParameteriv(src_texture, 0, GL_TEXTURE_HEIGHT, &src_texture_height); - glProgramUniform4f(vertex_program_, 0, src_x / float(src_texture_width), - src_y / float(src_texture_height), - src_width / float(src_texture_width), - src_height / float(src_texture_height)); + glProgramUniform4f(vertex_program_, 0, src_rect.x / float(src_texture_width), + src_rect.y / float(src_texture_height), + src_rect.width / float(src_texture_width), + src_rect.height / float(src_texture_height)); + glProgramUniform4f(vertex_program_, 1, float(dest_rect.x), float(dest_rect.y), + float(dest_rect.width), float(dest_rect.height)); // Useful for seeing the entire framebuffer/etc: // glProgramUniform4f(vertex_program_, 0, 0.0f, 0.0f, 1.0f, 1.0f); @@ -246,34 +251,27 @@ void Blitter::Draw(GLuint src_texture, int32_t src_x, int32_t src_y, glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } -void Blitter::BlitTexture2D(GLuint src_texture, int32_t src_x, int32_t src_y, - int32_t src_width, int32_t src_height, - int32_t dest_x, int32_t dest_y, int32_t dest_width, - int32_t dest_height, GLenum filter) { +void Blitter::BlitTexture2D(GLuint src_texture, Rect2D src_rect, + Rect2D dest_rect, GLenum filter) { SavedState state; state.Save(); - glViewport(dest_x, dest_y, dest_width, dest_height); glColorMaski(0, true, true, true, true); glDisable(GL_DEPTH_TEST); glDepthMask(false); glBindProgramPipeline(color_pipeline_); - Draw(src_texture, src_x, src_y, src_width, src_height, filter); + Draw(src_texture, src_rect, dest_rect, filter); state.Restore(); } -void Blitter::CopyColorTexture2D(GLuint src_texture, int32_t src_x, - int32_t src_y, int32_t src_width, - int32_t src_height, GLuint dest_texture, - int32_t dest_x, int32_t dest_y, - int32_t dest_width, int32_t dest_height, +void Blitter::CopyColorTexture2D(GLuint src_texture, Rect2D src_rect, + GLuint dest_texture, Rect2D dest_rect, GLenum filter) { SavedState state; state.Save(); - glViewport(dest_x, dest_y, dest_width, dest_height); glColorMaski(0, true, true, true, true); glDisable(GL_DEPTH_TEST); glDepthMask(false); @@ -283,7 +281,7 @@ void Blitter::CopyColorTexture2D(GLuint src_texture, int32_t src_x, dest_texture, 0); glNamedFramebufferDrawBuffer(scratch_framebuffer_, GL_COLOR_ATTACHMENT0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, scratch_framebuffer_); - Draw(src_texture, src_x, src_y, src_width, src_height, filter); + Draw(src_texture, src_rect, dest_rect, filter); glNamedFramebufferDrawBuffer(scratch_framebuffer_, GL_NONE); glNamedFramebufferTexture(scratch_framebuffer_, GL_COLOR_ATTACHMENT0, GL_NONE, 0); @@ -291,15 +289,11 @@ void Blitter::CopyColorTexture2D(GLuint src_texture, int32_t src_x, state.Restore(); } -void Blitter::CopyDepthTexture(GLuint src_texture, int32_t src_x, int32_t src_y, - int32_t src_width, int32_t src_height, - GLuint dest_texture, int32_t dest_x, - int32_t dest_y, int32_t dest_width, - int32_t dest_height) { +void Blitter::CopyDepthTexture(GLuint src_texture, Rect2D src_rect, + GLuint dest_texture, Rect2D dest_rect) { SavedState state; state.Save(); - glViewport(dest_x, dest_y, dest_width, dest_height); glColorMaski(0, false, false, false, false); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_ALWAYS); @@ -309,7 +303,7 @@ void Blitter::CopyDepthTexture(GLuint src_texture, int32_t src_x, int32_t src_y, glNamedFramebufferTexture(scratch_framebuffer_, GL_DEPTH_STENCIL_ATTACHMENT, dest_texture, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, scratch_framebuffer_); - Draw(src_texture, src_x, src_y, src_width, src_height, GL_NEAREST); + Draw(src_texture, src_rect, dest_rect, GL_NEAREST); glNamedFramebufferTexture(scratch_framebuffer_, GL_DEPTH_STENCIL_ATTACHMENT, GL_NONE, 0); diff --git a/src/xenia/gpu/gl4/blitter.h b/src/xenia/gpu/gl4/blitter.h index 2777195bb..eaa702d83 100644 --- a/src/xenia/gpu/gl4/blitter.h +++ b/src/xenia/gpu/gl4/blitter.h @@ -19,6 +19,18 @@ namespace xe { namespace gpu { namespace gl4 { +struct Rect2D { + int32_t x; + int32_t y; + int32_t width; + int32_t height; + Rect2D() : x(0), y(0), width(0), height(0) {} + Rect2D(int32_t x_, int32_t y_, int32_t width_, int32_t height_) + : x(x_), y(y_), width(width_), height(height_) {} + int32_t right() const { return x + width; } + int32_t bottom() const { return y + height; } +}; + class Blitter { public: Blitter(); @@ -27,24 +39,16 @@ class Blitter { bool Initialize(); void Shutdown(); - void BlitTexture2D(GLuint src_texture, int32_t src_x, int32_t src_y, - int32_t src_width, int32_t src_height, int32_t dest_x, - int32_t dest_y, int32_t dest_width, int32_t dest_height, + void BlitTexture2D(GLuint src_texture, Rect2D src_rect, Rect2D dest_rect, GLenum filter); - void CopyColorTexture2D(GLuint src_texture, int32_t src_x, int32_t src_y, - int32_t src_width, int32_t src_height, - GLuint dest_texture, int32_t dest_x, int32_t dest_y, - int32_t dest_width, int32_t dest_height, - GLenum filter); - void CopyDepthTexture(GLuint src_texture, int32_t src_x, int32_t src_y, - int32_t src_width, int32_t src_height, - GLuint dest_texture, int32_t dest_x, int32_t dest_y, - int32_t dest_width, int32_t dest_height); + void CopyColorTexture2D(GLuint src_texture, Rect2D src_rect, + GLuint dest_texture, Rect2D dest_rect, GLenum filter); + void CopyDepthTexture(GLuint src_texture, Rect2D src_rect, + GLuint dest_texture, Rect2D dest_rect); private: - void Draw(GLuint src_texture, int32_t src_x, int32_t src_y, int32_t src_width, - int32_t src_height, GLenum filter); + void Draw(GLuint src_texture, Rect2D src_rect, Rect2D dest_rect, GLenum filter); GLuint vertex_program_; GLuint color_fragment_program_; diff --git a/src/xenia/gpu/gl4/command_processor.cc b/src/xenia/gpu/gl4/command_processor.cc index adf5c638a..f41bec3dd 100644 --- a/src/xenia/gpu/gl4/command_processor.cc +++ b/src/xenia/gpu/gl4/command_processor.cc @@ -578,12 +578,16 @@ void CommandProcessor::IssueSwap() { // Guess frontbuffer dimensions. // Command buffer seems to set these right before the XE_SWAP. - uint32_t window_scissor_tl = regs[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL].u32; - uint32_t window_scissor_br = regs[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_BR].u32; - swap_params.x = window_scissor_tl & 0x7FFF; - swap_params.y = (window_scissor_tl >> 16) & 0x7FFF; - swap_params.width = window_scissor_br & 0x7FFF - swap_params.x; - swap_params.height = (window_scissor_br >> 16) & 0x7FFF - swap_params.y; + // uint32_t window_scissor_tl = regs[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_TL].u32; + // uint32_t window_scissor_br = regs[XE_GPU_REG_PA_SC_WINDOW_SCISSOR_BR].u32; + // swap_params.x = window_scissor_tl & 0x7FFF; + // swap_params.y = (window_scissor_tl >> 16) & 0x7FFF; + // swap_params.width = window_scissor_br & 0x7FFF - swap_params.x; + // swap_params.height = (window_scissor_br >> 16) & 0x7FFF - swap_params.y; + swap_params.x = 0; + swap_params.y = 0; + swap_params.width = 1280; + swap_params.height = 720; PrepareForWait(); swap_handler_(swap_params); @@ -2636,11 +2640,8 @@ bool CommandProcessor::IssueCopy() { // REG_A2XX_RB_COPY_DEST_OFFSET = A2XX_RB_COPY_DEST_OFFSET_X(tile->xoff) | // A2XX_RB_COPY_DEST_OFFSET_Y(tile->yoff); // but I can't seem to find something similar. - // Maybe scissor rect/window offset? - uint32_t x = 0; - uint32_t y = 0; - uint32_t w = copy_dest_pitch; - uint32_t h = copy_dest_height; + uint32_t width = copy_dest_pitch; + uint32_t height = copy_dest_height; uint32_t window_offset = regs[XE_GPU_REG_PA_SC_WINDOW_OFFSET].u32; int16_t window_offset_x = window_offset & 0x7FFF; @@ -2651,8 +2652,52 @@ bool CommandProcessor::IssueCopy() { if (window_offset_y & 0x4000) { window_offset_y |= 0x8000; } - // x = window_offset_x; - // y = window_offset_y; + + // HACK: vertices to use are always in vf0. + int copy_vertex_fetch_slot = 0; + int r = + XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + (copy_vertex_fetch_slot / 3) * 6; + const auto group = reinterpret_cast(®s.values[r]); + const xe_gpu_vertex_fetch_t* fetch = nullptr; + switch (copy_vertex_fetch_slot % 3) { + case 0: + fetch = &group->vertex_fetch_0; + break; + case 1: + fetch = &group->vertex_fetch_1; + break; + case 2: + fetch = &group->vertex_fetch_2; + break; + } + assert_true(fetch->type == 3); + assert_true(fetch->endian == 2); + assert_true(fetch->size == 6); + const uint8_t* vertex_addr = membase_ + (fetch->address << 2); + trace_writer_.WriteMemoryRead(fetch->address << 2, fetch->size * 4); + int32_t dest_min_x = int32_t(std::ceilf(std::min( + std::min( + GpuSwap(poly::load(vertex_addr + 0), Endian(fetch->endian)), + GpuSwap(poly::load(vertex_addr + 8), Endian(fetch->endian))), + GpuSwap(poly::load(vertex_addr + 16), Endian(fetch->endian))))); + int32_t dest_max_x = int32_t(std::ceilf(std::max( + std::max( + GpuSwap(poly::load(vertex_addr + 0), Endian(fetch->endian)), + GpuSwap(poly::load(vertex_addr + 8), Endian(fetch->endian))), + GpuSwap(poly::load(vertex_addr + 16), Endian(fetch->endian))))); + int32_t dest_min_y = int32_t(std::ceilf(std::min( + std::min( + GpuSwap(poly::load(vertex_addr + 4), Endian(fetch->endian)), + GpuSwap(poly::load(vertex_addr + 12), Endian(fetch->endian))), + GpuSwap(poly::load(vertex_addr + 20), Endian(fetch->endian))))); + int32_t dest_max_y = int32_t(std::ceilf(std::max( + std::max( + GpuSwap(poly::load(vertex_addr + 4), Endian(fetch->endian)), + GpuSwap(poly::load(vertex_addr + 12), Endian(fetch->endian))), + GpuSwap(poly::load(vertex_addr + 20), Endian(fetch->endian))))); + Rect2D dest_rect(dest_min_x, dest_min_y, dest_max_x - dest_min_x, + dest_max_y - dest_min_y); + Rect2D src_rect(0, 0, dest_rect.width, dest_rect.height); // Make active so glReadPixels reads from us. switch (copy_command) { @@ -2663,18 +2708,19 @@ bool CommandProcessor::IssueCopy() { // Source from a bound render target. // TODO(benvanik): RAW copy. last_framebuffer_texture_ = texture_cache_.CopyTexture( - context_->blitter(), copy_dest_base, x, y, w, h, + context_->blitter(), copy_dest_base, width, height, ColorFormatToTextureFormat(copy_dest_format), - copy_dest_swap ? true : false, color_targets[copy_src_select]); + copy_dest_swap ? true : false, color_targets[copy_src_select], + src_rect, dest_rect); if (!FLAGS_disable_framebuffer_readback) { // glReadPixels(x, y, w, h, read_format, read_type, ptr); } } else { // Source from the bound depth/stencil target. // TODO(benvanik): RAW copy. - texture_cache_.CopyTexture(context_->blitter(), copy_dest_base, x, y, w, - h, src_format, copy_dest_swap ? true : false, - depth_target); + texture_cache_.CopyTexture( + context_->blitter(), copy_dest_base, width, height, src_format, + copy_dest_swap ? true : false, depth_target, src_rect, dest_rect); if (!FLAGS_disable_framebuffer_readback) { // glReadPixels(x, y, w, h, GL_DEPTH_STENCIL, read_type, ptr); } @@ -2687,17 +2733,18 @@ bool CommandProcessor::IssueCopy() { // Either copy the readbuffer into an existing texture or create a new // one in the cache so we can service future upload requests. last_framebuffer_texture_ = texture_cache_.ConvertTexture( - context_->blitter(), copy_dest_base, x, y, w, h, + context_->blitter(), copy_dest_base, width, height, ColorFormatToTextureFormat(copy_dest_format), - copy_dest_swap ? true : false, color_targets[copy_src_select]); + copy_dest_swap ? true : false, color_targets[copy_src_select], + src_rect, dest_rect); if (!FLAGS_disable_framebuffer_readback) { // glReadPixels(x, y, w, h, read_format, read_type, ptr); } } else { // Source from the bound depth/stencil target. texture_cache_.ConvertTexture( - context_->blitter(), copy_dest_base, x, y, w, h, src_format, - copy_dest_swap ? true : false, depth_target); + context_->blitter(), copy_dest_base, width, height, src_format, + copy_dest_swap ? true : false, depth_target, src_rect, dest_rect); if (!FLAGS_disable_framebuffer_readback) { // glReadPixels(x, y, w, h, GL_DEPTH_STENCIL, read_type, ptr); } diff --git a/src/xenia/gpu/gl4/gl4_graphics_system.cc b/src/xenia/gpu/gl4/gl4_graphics_system.cc index f311668e6..0ed7d4691 100644 --- a/src/xenia/gpu/gl4/gl4_graphics_system.cc +++ b/src/xenia/gpu/gl4/gl4_graphics_system.cc @@ -262,10 +262,11 @@ void GL4GraphicsSystem::SwapHandler(const SwapParameters& swap_params) { // no-op. return; } + Rect2D src_rect(swap_params.x, swap_params.y, swap_params.width, + swap_params.height); + Rect2D dest_rect(0, 0, control_->width(), control_->height()); control_->context()->blitter()->BlitTexture2D( - swap_params.framebuffer_texture, swap_params.x, swap_params.y, - swap_params.width, swap_params.height, 0, 0, control_->width(), - control_->height(), GL_LINEAR); + swap_params.framebuffer_texture, src_rect, dest_rect, GL_LINEAR); }); } diff --git a/src/xenia/gpu/gl4/texture_cache.cc b/src/xenia/gpu/gl4/texture_cache.cc index 032e65b1c..3b0eba6ea 100644 --- a/src/xenia/gpu/gl4/texture_cache.cc +++ b/src/xenia/gpu/gl4/texture_cache.cc @@ -524,17 +524,19 @@ TextureCache::TextureEntry* TextureCache::LookupAddress(uint32_t guest_address, } GLuint TextureCache::CopyTexture(Blitter* blitter, uint32_t guest_address, - int32_t x, int32_t y, int32_t width, - int32_t height, TextureFormat format, - bool swap_channels, GLuint src_texture) { - return ConvertTexture(blitter, guest_address, x, y, width, height, format, - swap_channels, src_texture); + uint32_t width, uint32_t height, + TextureFormat format, bool swap_channels, + GLuint src_texture, Rect2D src_rect, + Rect2D dest_rect) { + return ConvertTexture(blitter, guest_address, width, height, format, + swap_channels, src_texture, src_rect, dest_rect); } GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, - int32_t x, int32_t y, int32_t width, - int32_t height, TextureFormat format, - bool swap_channels, GLuint src_texture) { + uint32_t width, uint32_t height, + TextureFormat format, bool swap_channels, + GLuint src_texture, Rect2D src_rect, + Rect2D dest_rect) { const auto& config = texture_configs[uint32_t(format)]; if (config.format == GL_INVALID_ENUM) { assert_always("Unhandled destination texture format"); @@ -549,12 +551,11 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, // Have existing texture. assert_false(texture_entry->pending_invalidation); if (config.format == GL_DEPTH_STENCIL) { - blitter->CopyDepthTexture(src_texture, x, y, width, height, - texture_entry->handle, 0, 0, width, height); + blitter->CopyDepthTexture(src_texture, src_rect, texture_entry->handle, + dest_rect); } else { - blitter->CopyColorTexture2D(src_texture, x, y, width, height, - texture_entry->handle, 0, 0, width, height, - GL_LINEAR); + blitter->CopyColorTexture2D(src_texture, src_rect, texture_entry->handle, + dest_rect, GL_LINEAR); } // HACK: remove texture from write watch list so readback won't kill us. @@ -574,12 +575,11 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, entry->height == height && entry->format == format) { // Found an existing entry - just reupload. if (config.format == GL_DEPTH_STENCIL) { - blitter->CopyDepthTexture(src_texture, x, y, width, height, - entry->handle, 0, 0, width, height); + blitter->CopyDepthTexture(src_texture, src_rect, entry->handle, + dest_rect); } else { - blitter->CopyColorTexture2D(src_texture, x, y, width, height, - entry->handle, 0, 0, width, height, - GL_LINEAR); + blitter->CopyColorTexture2D(src_texture, src_rect, entry->handle, + dest_rect, GL_LINEAR); } return entry->handle; } @@ -600,11 +600,10 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, glTextureParameteri(entry->handle, GL_TEXTURE_MAX_LEVEL, 1); glTextureStorage2D(entry->handle, 1, config.internal_format, width, height); if (config.format == GL_DEPTH_STENCIL) { - blitter->CopyDepthTexture(src_texture, x, y, width, height, entry->handle, - 0, 0, width, height); + blitter->CopyDepthTexture(src_texture, src_rect, entry->handle, dest_rect); } else { - blitter->CopyColorTexture2D(src_texture, x, y, width, height, entry->handle, - 0, 0, width, height, GL_LINEAR); + blitter->CopyColorTexture2D(src_texture, src_rect, entry->handle, dest_rect, + GL_LINEAR); } GLuint handle = entry->handle; diff --git a/src/xenia/gpu/gl4/texture_cache.h b/src/xenia/gpu/gl4/texture_cache.h index 7a4828944..4e85ca299 100644 --- a/src/xenia/gpu/gl4/texture_cache.h +++ b/src/xenia/gpu/gl4/texture_cache.h @@ -59,14 +59,13 @@ class TextureCache { TextureEntryView* Demand(const TextureInfo& texture_info, const SamplerInfo& sampler_info); - GLuint CopyTexture(Blitter* blitter, uint32_t guest_address, int32_t x, - int32_t y, int32_t width, int32_t height, - TextureFormat format, bool swap_channels, - GLuint src_texture); - GLuint ConvertTexture(Blitter* blitter, uint32_t guest_address, int32_t x, - int32_t y, int32_t width, int32_t height, - TextureFormat format, bool swap_channels, - GLuint src_texture); + GLuint CopyTexture(Blitter* blitter, uint32_t guest_address, uint32_t width, + uint32_t height, TextureFormat format, bool swap_channels, + GLuint src_texture, Rect2D src_rect, Rect2D dest_rect); + GLuint ConvertTexture(Blitter* blitter, uint32_t guest_address, + uint32_t width, uint32_t height, TextureFormat format, + bool swap_channels, GLuint src_texture, Rect2D src_rect, + Rect2D dest_rect); private: struct ReadBufferTexture {