diff --git a/src/xenia/gpu/gl4/blitter.cc b/src/xenia/gpu/gl4/blitter.cc index 13b3ebe3e..575c40b77 100644 --- a/src/xenia/gpu/gl4/blitter.cc +++ b/src/xenia/gpu/gl4/blitter.cc @@ -229,7 +229,7 @@ void Blitter::Draw(GLuint src_texture, Rect2D src_rect, Rect2D dest_rect, break; } - glViewport(0, 0, dest_rect.width, dest_rect.height); + glViewport(dest_rect.x, dest_rect.y, dest_rect.width, dest_rect.height); // TODO(benvanik): avoid this? GLint src_texture_width; diff --git a/src/xenia/gpu/gl4/command_processor.cc b/src/xenia/gpu/gl4/command_processor.cc index 8d6f969cf..dc1333cbb 100644 --- a/src/xenia/gpu/gl4/command_processor.cc +++ b/src/xenia/gpu/gl4/command_processor.cc @@ -578,16 +578,12 @@ 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; - swap_params.x = 0; - swap_params.y = 0; - swap_params.width = 1280; - swap_params.height = 720; + 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; PrepareForWait(); swap_handler_(swap_params); @@ -2208,6 +2204,7 @@ CommandProcessor::UpdateStatus CommandProcessor::UpdateDepthStencilState() { } else { glDisable(GL_DEPTH_TEST); } + // glDisable(GL_DEPTH_TEST); // A2XX_RB_DEPTHCONTROL_Z_WRITE_ENABLE glDepthMask((regs.rb_depthcontrol & 0x00000004) ? GL_TRUE : GL_FALSE); // A2XX_RB_DEPTHCONTROL_EARLY_Z_ENABLE @@ -2631,17 +2628,14 @@ bool CommandProcessor::IssueCopy() { // glPixelStorei(GL_PACK_ROW_LENGTH, 0); // glPixelStorei(GL_PACK_IMAGE_HEIGHT, 0); - // Destination pointer in guest memory. - // We have GL throw bytes directly into it. - // TODO(benvanik): copy to staging texture then PBO back? - void* ptr = membase_ + GpuToCpu(copy_dest_base); - // TODO(benvanik): any way to scissor this? a200 has: // 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. - uint32_t width = copy_dest_pitch; - uint32_t height = copy_dest_height; + uint32_t dest_logical_width = copy_dest_pitch; + uint32_t dest_logical_height = copy_dest_height; + uint32_t dest_block_width = poly::round_up(dest_logical_width, 32); + uint32_t dest_block_height = poly::round_up(dest_logical_height, 32); uint32_t window_offset = regs[XE_GPU_REG_PA_SC_WINDOW_OFFSET].u32; int16_t window_offset_x = window_offset & 0x7FFF; @@ -2699,6 +2693,19 @@ bool CommandProcessor::IssueCopy() { dest_max_y - dest_min_y); Rect2D src_rect(0, 0, dest_rect.width, dest_rect.height); + // The dest base address passed in has already been offset by the window + // offset, so to ensure texture lookup works we need to offset it. + // TODO(benvanik): allow texture cache to lookup partial textures. + // TODO(benvanik): change based on format. + int32_t dest_offset = window_offset_y * copy_dest_pitch * 4; + dest_offset += window_offset_x * 32 * 4; + copy_dest_base += dest_offset; + + // Destination pointer in guest memory. + // We have GL throw bytes directly into it. + // TODO(benvanik): copy to staging texture then PBO back? + void* ptr = membase_ + GpuToCpu(copy_dest_base); + // Make active so glReadPixels reads from us. switch (copy_command) { case CopyCommand::kRaw: { @@ -2708,7 +2715,8 @@ bool CommandProcessor::IssueCopy() { // Source from a bound render target. // TODO(benvanik): RAW copy. last_framebuffer_texture_ = texture_cache_.CopyTexture( - context_->blitter(), copy_dest_base, width, height, + context_->blitter(), copy_dest_base, dest_logical_width, + dest_logical_height, dest_block_width, dest_block_height, ColorFormatToTextureFormat(copy_dest_format), copy_dest_swap ? true : false, color_targets[copy_src_select], src_rect, dest_rect); @@ -2718,9 +2726,11 @@ bool CommandProcessor::IssueCopy() { } else { // Source from the bound depth/stencil target. // TODO(benvanik): RAW copy. - texture_cache_.CopyTexture( - context_->blitter(), copy_dest_base, width, height, src_format, - copy_dest_swap ? true : false, depth_target, src_rect, dest_rect); + texture_cache_.CopyTexture(context_->blitter(), copy_dest_base, + dest_logical_width, dest_logical_height, + dest_block_width, dest_block_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); } @@ -2733,7 +2743,8 @@ 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, width, height, + context_->blitter(), copy_dest_base, dest_logical_width, + dest_logical_height, dest_block_width, dest_block_height, ColorFormatToTextureFormat(copy_dest_format), copy_dest_swap ? true : false, color_targets[copy_src_select], src_rect, dest_rect); @@ -2742,9 +2753,11 @@ bool CommandProcessor::IssueCopy() { } } else { // Source from the bound depth/stencil target. - texture_cache_.ConvertTexture( - context_->blitter(), copy_dest_base, width, height, src_format, - copy_dest_swap ? true : false, depth_target, src_rect, dest_rect); + texture_cache_.ConvertTexture(context_->blitter(), copy_dest_base, + dest_logical_width, dest_logical_height, + dest_block_width, dest_block_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/texture_cache.cc b/src/xenia/gpu/gl4/texture_cache.cc index 3b0eba6ea..e6afa5304 100644 --- a/src/xenia/gpu/gl4/texture_cache.cc +++ b/src/xenia/gpu/gl4/texture_cache.cc @@ -409,8 +409,8 @@ TextureCache::TextureEntry* TextureCache::LookupOrInsertTexture( it != read_buffer_textures_.end(); ++it) { auto read_buffer_entry = *it; if (read_buffer_entry->guest_address == texture_info.guest_address && - read_buffer_entry->width == texture_info.size_2d.logical_width && - read_buffer_entry->height == texture_info.size_2d.logical_height) { + read_buffer_entry->block_width == texture_info.size_2d.block_width && + read_buffer_entry->block_height == texture_info.size_2d.block_height) { // Found! Acquire the handle and remove the readbuffer entry. read_buffer_textures_.erase(it); entry->handle = read_buffer_entry->handle; @@ -515,8 +515,8 @@ TextureCache::TextureEntry* TextureCache::LookupAddress(uint32_t guest_address, const auto& texture_info = it->second->texture_info; if (texture_info.guest_address == guest_address && texture_info.dimension == Dimension::k2D && - texture_info.size_2d.logical_width == width && - texture_info.size_2d.logical_height == height) { + texture_info.size_2d.input_width == width && + texture_info.size_2d.input_height == height) { return it->second; } } @@ -524,16 +524,20 @@ TextureCache::TextureEntry* TextureCache::LookupAddress(uint32_t guest_address, } GLuint TextureCache::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) { - return ConvertTexture(blitter, guest_address, width, height, format, - swap_channels, src_texture, src_rect, dest_rect); + uint32_t logical_width, + uint32_t logical_height, uint32_t block_width, + uint32_t block_height, TextureFormat format, + bool swap_channels, GLuint src_texture, + Rect2D src_rect, Rect2D dest_rect) { + return ConvertTexture(blitter, guest_address, logical_width, logical_height, + block_width, block_height, format, swap_channels, + src_texture, src_rect, dest_rect); } GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, - uint32_t width, uint32_t height, + uint32_t logical_width, + uint32_t logical_height, + uint32_t block_width, uint32_t block_height, TextureFormat format, bool swap_channels, GLuint src_texture, Rect2D src_rect, Rect2D dest_rect) { @@ -546,7 +550,8 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, // See if we have used a texture at this address before. If we have, we can // reuse it. // TODO(benvanik): better lookup matching format/etc? - auto texture_entry = LookupAddress(guest_address, width, height, format); + auto texture_entry = + LookupAddress(guest_address, block_width, block_height, format); if (texture_entry) { // Have existing texture. assert_false(texture_entry->pending_invalidation); @@ -571,8 +576,9 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, for (auto it = read_buffer_textures_.begin(); it != read_buffer_textures_.end(); ++it) { const auto& entry = *it; - if (entry->guest_address == guest_address && entry->width == width && - entry->height == height && entry->format == format) { + if (entry->guest_address == guest_address && + entry->logical_width == logical_width && + entry->logical_height == logical_height && entry->format == format) { // Found an existing entry - just reupload. if (config.format == GL_DEPTH_STENCIL) { blitter->CopyDepthTexture(src_texture, src_rect, entry->handle, @@ -591,14 +597,17 @@ GLuint TextureCache::ConvertTexture(Blitter* blitter, uint32_t guest_address, // of time we'll dump it. auto entry = std::make_unique(); entry->guest_address = guest_address; - entry->width = width; - entry->height = height; + entry->logical_width = logical_width; + entry->logical_height = logical_height; + entry->block_width = block_width; + entry->block_height = block_height; entry->format = format; glCreateTextures(GL_TEXTURE_2D, 1, &entry->handle); glTextureParameteri(entry->handle, GL_TEXTURE_BASE_LEVEL, 0); glTextureParameteri(entry->handle, GL_TEXTURE_MAX_LEVEL, 1); - glTextureStorage2D(entry->handle, 1, config.internal_format, width, height); + glTextureStorage2D(entry->handle, 1, config.internal_format, logical_width, + logical_height); if (config.format == GL_DEPTH_STENCIL) { blitter->CopyDepthTexture(src_texture, src_rect, entry->handle, dest_rect); } else { diff --git a/src/xenia/gpu/gl4/texture_cache.h b/src/xenia/gpu/gl4/texture_cache.h index 4e85ca299..cc2997d57 100644 --- a/src/xenia/gpu/gl4/texture_cache.h +++ b/src/xenia/gpu/gl4/texture_cache.h @@ -59,19 +59,24 @@ class TextureCache { TextureEntryView* Demand(const TextureInfo& texture_info, const SamplerInfo& sampler_info); - GLuint CopyTexture(Blitter* blitter, uint32_t guest_address, uint32_t width, - uint32_t height, TextureFormat format, bool swap_channels, + GLuint CopyTexture(Blitter* blitter, uint32_t guest_address, + uint32_t logical_width, uint32_t logical_height, + uint32_t block_width, uint32_t block_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); + uint32_t logical_width, uint32_t logical_height, + uint32_t block_width, uint32_t block_height, + TextureFormat format, bool swap_channels, + GLuint src_texture, Rect2D src_rect, Rect2D dest_rect); private: struct ReadBufferTexture { uint32_t guest_address; - uint32_t width; - uint32_t height; + uint32_t logical_width; + uint32_t logical_height; + uint32_t block_width; + uint32_t block_height; TextureFormat format; GLuint handle; };