mirror of
https://github.com/RPCSX/rpcsx.git
synced 2025-12-06 07:12:14 +01:00
214 lines
7.1 KiB
C++
214 lines
7.1 KiB
C++
#include "stdafx.h"
|
|
#include "blitter.h"
|
|
#include "state_tracker.hpp"
|
|
|
|
#include "../GLTexture.h" // TODO: This system also needs to be refactored
|
|
#include "../GLOverlays.h"
|
|
|
|
namespace gl
|
|
{
|
|
blitter* g_hw_blitter = nullptr;
|
|
|
|
void blitter::copy_image(gl::command_context&, const texture* src, const texture* dst, int src_level, int dst_level, const position3i& src_offset, const position3i& dst_offset, const size3i& size) const
|
|
{
|
|
ensure(src_level == 0);
|
|
|
|
// Typeless bypass for BGRA8
|
|
std::unique_ptr<gl::texture> temp_image;
|
|
const texture* real_src = src;
|
|
|
|
glCopyImageSubData(real_src->id(), static_cast<GLenum>(real_src->get_target()), src_level,
|
|
src_offset.x, src_offset.y, src_offset.z,
|
|
dst->id(), static_cast<GLenum>(dst->get_target()), dst_level,
|
|
dst_offset.x, dst_offset.y, dst_offset.z, size.width, size.height, size.depth);
|
|
}
|
|
|
|
void blitter::scale_image(gl::command_context& cmd, const texture* src, texture* dst, areai src_rect, areai dst_rect,
|
|
bool linear_interpolation, const rsx::typeless_xfer& xfer_info)
|
|
{
|
|
std::unique_ptr<texture> typeless_src;
|
|
std::unique_ptr<texture> typeless_dst;
|
|
const gl::texture* real_src = src;
|
|
const gl::texture* real_dst = dst;
|
|
|
|
// Optimization pass; check for pass-through data transfer
|
|
if (!xfer_info.flip_horizontal && !xfer_info.flip_vertical && src_rect.height() == dst_rect.height())
|
|
{
|
|
auto src_w = src_rect.width();
|
|
auto dst_w = dst_rect.width();
|
|
|
|
if (xfer_info.src_is_typeless) src_w = static_cast<int>(src_w * xfer_info.src_scaling_hint);
|
|
if (xfer_info.dst_is_typeless) dst_w = static_cast<int>(dst_w * xfer_info.dst_scaling_hint);
|
|
|
|
if (src_w == dst_w)
|
|
{
|
|
// Final dimensions are a match
|
|
if (xfer_info.src_is_typeless || xfer_info.dst_is_typeless)
|
|
{
|
|
const coord3i src_region = { { src_rect.x1, src_rect.y1, 0 }, { src_rect.width(), src_rect.height(), 1 } };
|
|
const coord3i dst_region = { { dst_rect.x1, dst_rect.y1, 0 }, { dst_rect.width(), dst_rect.height(), 1 } };
|
|
gl::copy_typeless(cmd, dst, src, static_cast<coord3u>(dst_region), static_cast<coord3u>(src_region));
|
|
}
|
|
else
|
|
{
|
|
copy_image(cmd, src, dst, 0, 0, position3i{ src_rect.x1, src_rect.y1, 0u }, position3i{ dst_rect.x1, dst_rect.y1, 0 }, size3i{ src_rect.width(), src_rect.height(), 1 });
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (xfer_info.src_is_typeless)
|
|
{
|
|
const auto internal_fmt = xfer_info.src_native_format_override ?
|
|
GLenum(xfer_info.src_native_format_override) :
|
|
get_sized_internal_format(xfer_info.src_gcm_format);
|
|
|
|
if (static_cast<gl::texture::internal_format>(internal_fmt) != src->get_internal_format())
|
|
{
|
|
const u16 internal_width = static_cast<u16>(src->width() * xfer_info.src_scaling_hint);
|
|
typeless_src = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, src->height(), 1, 1, internal_fmt);
|
|
copy_typeless(cmd, typeless_src.get(), src);
|
|
|
|
real_src = typeless_src.get();
|
|
src_rect.x1 = static_cast<u16>(src_rect.x1 * xfer_info.src_scaling_hint);
|
|
src_rect.x2 = static_cast<u16>(src_rect.x2 * xfer_info.src_scaling_hint);
|
|
}
|
|
}
|
|
|
|
if (xfer_info.dst_is_typeless)
|
|
{
|
|
const auto internal_fmt = xfer_info.dst_native_format_override ?
|
|
GLenum(xfer_info.dst_native_format_override) :
|
|
get_sized_internal_format(xfer_info.dst_gcm_format);
|
|
|
|
if (static_cast<gl::texture::internal_format>(internal_fmt) != dst->get_internal_format())
|
|
{
|
|
const auto internal_width = static_cast<u16>(dst->width() * xfer_info.dst_scaling_hint);
|
|
typeless_dst = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, dst->height(), 1, 1, internal_fmt);
|
|
copy_typeless(cmd, typeless_dst.get(), dst);
|
|
|
|
real_dst = typeless_dst.get();
|
|
dst_rect.x1 = static_cast<u16>(dst_rect.x1 * xfer_info.dst_scaling_hint);
|
|
dst_rect.x2 = static_cast<u16>(dst_rect.x2 * xfer_info.dst_scaling_hint);
|
|
}
|
|
}
|
|
|
|
ensure(real_src->aspect() == real_dst->aspect());
|
|
|
|
if (src_rect.width() == dst_rect.width() && src_rect.height() == dst_rect.height() &&
|
|
!src_rect.is_flipped() && !dst_rect.is_flipped())
|
|
{
|
|
copy_image(cmd, real_src, real_dst, 0, 0, position3i{ src_rect.x1, src_rect.y1, 0 }, position3i{ dst_rect.x1, dst_rect.y1, 0 }, size3i{ src_rect.width(), src_rect.height(), 1 });
|
|
}
|
|
else
|
|
{
|
|
const bool is_depth_copy = (real_src->aspect() != image_aspect::color);
|
|
const filter interp = (linear_interpolation && !is_depth_copy) ? filter::linear : filter::nearest;
|
|
gl::fbo::attachment::type attachment;
|
|
gl::buffers target;
|
|
|
|
if (is_depth_copy)
|
|
{
|
|
if (real_dst->aspect() & gl::image_aspect::stencil)
|
|
{
|
|
attachment = fbo::attachment::type::depth_stencil;
|
|
target = gl::buffers::depth_stencil;
|
|
}
|
|
else
|
|
{
|
|
attachment = fbo::attachment::type::depth;
|
|
target = gl::buffers::depth;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
attachment = fbo::attachment::type::color;
|
|
target = gl::buffers::color;
|
|
}
|
|
|
|
cmd->disable(GL_SCISSOR_TEST);
|
|
|
|
save_binding_state saved;
|
|
|
|
gl::fbo::attachment src_att{ blit_src, static_cast<fbo::attachment::type>(attachment) };
|
|
src_att = *real_src;
|
|
|
|
gl::fbo::attachment dst_att{ blit_dst, static_cast<fbo::attachment::type>(attachment) };
|
|
dst_att = *real_dst;
|
|
|
|
if (xfer_info.flip_horizontal)
|
|
{
|
|
src_rect.flip_horizontal();
|
|
}
|
|
|
|
if (xfer_info.flip_vertical)
|
|
{
|
|
src_rect.flip_vertical();
|
|
}
|
|
|
|
blit_src.blit(blit_dst, src_rect, dst_rect, target, interp);
|
|
|
|
// Release the attachments explicitly (not doing so causes glitches, e.g Journey Menu)
|
|
src_att = GL_NONE;
|
|
dst_att = GL_NONE;
|
|
}
|
|
|
|
if (xfer_info.dst_is_typeless)
|
|
{
|
|
// Transfer contents from typeless dst back to original dst
|
|
copy_typeless(cmd, dst, typeless_dst.get());
|
|
}
|
|
}
|
|
|
|
void blitter::fast_clear_image(gl::command_context& cmd, const texture* dst, const color4f& color)
|
|
{
|
|
save_binding_state saved;
|
|
|
|
blit_dst.bind();
|
|
blit_dst.color[0] = *dst;
|
|
blit_dst.check();
|
|
|
|
cmd->clear_color(color);
|
|
cmd->color_maski(0, true, true, true, true);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
blit_dst.color[0] = GL_NONE;
|
|
}
|
|
|
|
void blitter::fast_clear_image(gl::command_context& cmd, const texture* dst, float /*depth*/, u8 /*stencil*/)
|
|
{
|
|
fbo::attachment::type attachment;
|
|
GLbitfield clear_mask;
|
|
|
|
switch (const auto fmt = dst->get_internal_format())
|
|
{
|
|
case texture::internal_format::depth16:
|
|
case texture::internal_format::depth32f:
|
|
clear_mask = GL_DEPTH_BUFFER_BIT;
|
|
attachment = fbo::attachment::type::depth;
|
|
break;
|
|
case texture::internal_format::depth24_stencil8:
|
|
case texture::internal_format::depth32f_stencil8:
|
|
clear_mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
|
attachment = fbo::attachment::type::depth_stencil;
|
|
break;
|
|
default:
|
|
fmt::throw_exception("Invalid texture passed to clear depth function, format=0x%x", static_cast<u32>(fmt));
|
|
}
|
|
|
|
save_binding_state saved;
|
|
fbo::attachment attach_point{ blit_dst, attachment };
|
|
|
|
blit_dst.bind();
|
|
attach_point = *dst;
|
|
blit_dst.check();
|
|
|
|
cmd->depth_mask(GL_TRUE);
|
|
cmd->stencil_mask(0xFF);
|
|
|
|
glClear(clear_mask);
|
|
attach_point = GL_NONE;
|
|
}
|
|
}
|