2018-09-19 00:21:57 +02:00
|
|
|
|
#pragma once
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <exception>
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
#include <functional>
|
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
#include <memory>
|
2017-02-28 09:13:50 +01:00
|
|
|
|
#include <thread>
|
|
|
|
|
|
#include <condition_variable>
|
2017-03-29 21:27:29 +02:00
|
|
|
|
#include <chrono>
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2017-07-27 15:29:08 +02:00
|
|
|
|
#include "Utilities/mutex.h"
|
2017-06-22 20:25:58 +02:00
|
|
|
|
#include "Emu/System.h"
|
2016-09-18 07:19:26 +02:00
|
|
|
|
#include "GLRenderTargets.h"
|
2017-11-30 19:50:19 +01:00
|
|
|
|
#include "GLOverlays.h"
|
2016-02-15 10:50:14 +01:00
|
|
|
|
#include "../Common/TextureUtils.h"
|
2017-09-08 16:52:13 +02:00
|
|
|
|
#include "../Common/texture_cache.h"
|
2017-03-29 21:27:29 +02:00
|
|
|
|
#include "../../Memory/vm.h"
|
2017-04-23 11:32:37 +02:00
|
|
|
|
#include "../rsx_utils.h"
|
|
|
|
|
|
|
2017-02-16 19:29:56 +01:00
|
|
|
|
class GLGSRender;
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2017-02-13 15:22:25 +01:00
|
|
|
|
namespace gl
|
|
|
|
|
|
{
|
2017-09-28 20:32:00 +02:00
|
|
|
|
class blitter;
|
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
extern GLenum get_sized_internal_format(u32);
|
2018-04-07 17:16:52 +02:00
|
|
|
|
extern void copy_typeless(texture*, const texture*);
|
2017-09-28 20:32:00 +02:00
|
|
|
|
extern blitter *g_hw_blitter;
|
|
|
|
|
|
|
|
|
|
|
|
class blitter
|
|
|
|
|
|
{
|
|
|
|
|
|
fbo blit_src;
|
|
|
|
|
|
fbo blit_dst;
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
|
|
void init()
|
|
|
|
|
|
{
|
|
|
|
|
|
blit_src.create();
|
|
|
|
|
|
blit_dst.create();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void destroy()
|
|
|
|
|
|
{
|
|
|
|
|
|
blit_dst.remove();
|
|
|
|
|
|
blit_src.remove();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 17:16:52 +02:00
|
|
|
|
void scale_image(const texture* src, texture* dst, areai src_rect, areai dst_rect, bool linear_interpolation,
|
|
|
|
|
|
bool is_depth_copy, const rsx::typeless_xfer& xfer_info)
|
2017-09-28 20:32:00 +02:00
|
|
|
|
{
|
2018-04-07 17:16:52 +02:00
|
|
|
|
std::unique_ptr<texture> typeless_src;
|
|
|
|
|
|
std::unique_ptr<texture> typeless_dst;
|
|
|
|
|
|
u32 src_id = src->id();
|
|
|
|
|
|
u32 dst_id = dst->id();
|
|
|
|
|
|
|
|
|
|
|
|
if (xfer_info.src_is_typeless)
|
|
|
|
|
|
{
|
|
|
|
|
|
const auto internal_width = (u16)(src->width() * xfer_info.src_scaling_hint);
|
|
|
|
|
|
const auto internal_fmt = get_sized_internal_format(xfer_info.src_gcm_format);
|
|
|
|
|
|
typeless_src = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, src->height(), 1, 1, internal_fmt);
|
|
|
|
|
|
copy_typeless(typeless_src.get(), src);
|
|
|
|
|
|
|
|
|
|
|
|
src_id = typeless_src->id();
|
|
|
|
|
|
src_rect.x1 = (u16)(src_rect.x1 * xfer_info.src_scaling_hint);
|
|
|
|
|
|
src_rect.x2 = (u16)(src_rect.x2 * xfer_info.src_scaling_hint);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (xfer_info.dst_is_typeless)
|
|
|
|
|
|
{
|
|
|
|
|
|
const auto internal_width = (u16)(dst->width() * xfer_info.dst_scaling_hint);
|
|
|
|
|
|
const auto internal_fmt = get_sized_internal_format(xfer_info.dst_gcm_format);
|
|
|
|
|
|
typeless_dst = std::make_unique<texture>(GL_TEXTURE_2D, internal_width, dst->height(), 1, 1, internal_fmt);
|
|
|
|
|
|
copy_typeless(typeless_dst.get(), dst);
|
|
|
|
|
|
|
|
|
|
|
|
dst_id = typeless_dst->id();
|
|
|
|
|
|
dst_rect.x1 = (u16)(dst_rect.x1 * xfer_info.dst_scaling_hint);
|
|
|
|
|
|
dst_rect.x2 = (u16)(dst_rect.x2 * xfer_info.dst_scaling_hint);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-28 20:32:00 +02:00
|
|
|
|
s32 old_fbo = 0;
|
|
|
|
|
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo);
|
|
|
|
|
|
|
2018-06-04 18:57:16 +02:00
|
|
|
|
filter interp = (linear_interpolation && !is_depth_copy) ? filter::linear : filter::nearest;
|
|
|
|
|
|
GLenum attachment;
|
|
|
|
|
|
gl::buffers target;
|
|
|
|
|
|
|
|
|
|
|
|
if (is_depth_copy)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (src->get_internal_format() == gl::texture::internal_format::depth16 ||
|
|
|
|
|
|
dst->get_internal_format() == gl::texture::internal_format::depth16)
|
|
|
|
|
|
{
|
|
|
|
|
|
attachment = GL_DEPTH_ATTACHMENT;
|
|
|
|
|
|
target = gl::buffers::depth;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
attachment = GL_DEPTH_STENCIL_ATTACHMENT;
|
|
|
|
|
|
target = gl::buffers::depth_stencil;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
attachment = GL_COLOR_ATTACHMENT0;
|
|
|
|
|
|
target = gl::buffers::color;
|
|
|
|
|
|
}
|
2017-09-28 20:32:00 +02:00
|
|
|
|
|
|
|
|
|
|
blit_src.bind();
|
2018-04-07 17:16:52 +02:00
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, src_id, 0);
|
2017-09-28 20:32:00 +02:00
|
|
|
|
blit_src.check();
|
|
|
|
|
|
|
|
|
|
|
|
blit_dst.bind();
|
2018-04-07 17:16:52 +02:00
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, dst_id, 0);
|
2017-09-28 20:32:00 +02:00
|
|
|
|
blit_dst.check();
|
|
|
|
|
|
|
|
|
|
|
|
GLboolean scissor_test_enabled = glIsEnabled(GL_SCISSOR_TEST);
|
|
|
|
|
|
if (scissor_test_enabled)
|
|
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
|
|
|
2018-06-04 18:57:16 +02:00
|
|
|
|
blit_src.blit(blit_dst, src_rect, dst_rect, target, interp);
|
2017-09-28 20:32:00 +02:00
|
|
|
|
|
2018-04-07 17:16:52 +02:00
|
|
|
|
if (xfer_info.dst_is_typeless)
|
|
|
|
|
|
{
|
|
|
|
|
|
//Transfer contents from typeless dst back to original dst
|
|
|
|
|
|
copy_typeless(dst, typeless_dst.get());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-02 15:53:27 +02:00
|
|
|
|
blit_src.bind();
|
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, GL_NONE, 0);
|
|
|
|
|
|
|
|
|
|
|
|
blit_dst.bind();
|
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, GL_NONE, 0);
|
|
|
|
|
|
|
2017-09-28 20:32:00 +02:00
|
|
|
|
if (scissor_test_enabled)
|
|
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, old_fbo);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2017-09-08 16:52:13 +02:00
|
|
|
|
|
2017-09-18 19:22:34 +02:00
|
|
|
|
class cached_texture_section : public rsx::cached_texture_section
|
2017-02-13 15:22:25 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
private:
|
|
|
|
|
|
fence m_fence;
|
2018-02-10 09:52:44 +01:00
|
|
|
|
u32 pbo_id = 0;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
u32 pbo_size = 0;
|
2017-02-13 15:22:25 +01:00
|
|
|
|
|
2018-07-17 18:42:51 +02:00
|
|
|
|
gl::viewable_image* vram_texture = nullptr;
|
2018-04-07 12:19:49 +02:00
|
|
|
|
|
2018-07-17 18:42:51 +02:00
|
|
|
|
std::unique_ptr<gl::viewable_image> managed_texture;
|
2018-04-07 12:19:49 +02:00
|
|
|
|
std::unique_ptr<gl::texture> scaled_texture;
|
2017-02-16 19:29:56 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
texture::format format = texture::format::rgba;
|
|
|
|
|
|
texture::type type = texture::type::ubyte;
|
2017-11-29 15:05:36 +01:00
|
|
|
|
rsx::surface_antialiasing aa_mode = rsx::surface_antialiasing::center_1_sample;
|
2017-02-13 15:22:25 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
u8 get_pixel_size(texture::format fmt_, texture::type type_)
|
|
|
|
|
|
{
|
|
|
|
|
|
u8 size = 1;
|
|
|
|
|
|
switch (type_)
|
|
|
|
|
|
{
|
|
|
|
|
|
case texture::type::ubyte:
|
|
|
|
|
|
case texture::type::sbyte:
|
|
|
|
|
|
break;
|
|
|
|
|
|
case texture::type::ushort:
|
|
|
|
|
|
case texture::type::sshort:
|
|
|
|
|
|
case texture::type::f16:
|
|
|
|
|
|
size = 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case texture::type::ushort_5_6_5:
|
|
|
|
|
|
case texture::type::ushort_5_6_5_rev:
|
|
|
|
|
|
case texture::type::ushort_4_4_4_4:
|
|
|
|
|
|
case texture::type::ushort_4_4_4_4_rev:
|
|
|
|
|
|
case texture::type::ushort_5_5_5_1:
|
|
|
|
|
|
case texture::type::ushort_1_5_5_5_rev:
|
|
|
|
|
|
return 2;
|
|
|
|
|
|
case texture::type::uint_8_8_8_8:
|
|
|
|
|
|
case texture::type::uint_8_8_8_8_rev:
|
|
|
|
|
|
case texture::type::uint_10_10_10_2:
|
|
|
|
|
|
case texture::type::uint_2_10_10_10_rev:
|
|
|
|
|
|
case texture::type::uint_24_8:
|
|
|
|
|
|
return 4;
|
|
|
|
|
|
case texture::type::f32:
|
|
|
|
|
|
case texture::type::sint:
|
|
|
|
|
|
case texture::type::uint:
|
|
|
|
|
|
size = 4;
|
|
|
|
|
|
break;
|
2017-11-02 07:29:17 +01:00
|
|
|
|
default:
|
|
|
|
|
|
LOG_ERROR(RSX, "Unsupported texture type");
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (fmt_)
|
|
|
|
|
|
{
|
|
|
|
|
|
case texture::format::r:
|
|
|
|
|
|
break;
|
|
|
|
|
|
case texture::format::rg:
|
|
|
|
|
|
size *= 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case texture::format::rgb:
|
|
|
|
|
|
case texture::format::bgr:
|
|
|
|
|
|
size *= 3;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case texture::format::rgba:
|
|
|
|
|
|
case texture::format::bgra:
|
|
|
|
|
|
size *= 4;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
//Depth formats..
|
|
|
|
|
|
case texture::format::depth:
|
|
|
|
|
|
size = 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case texture::format::depth_stencil:
|
|
|
|
|
|
size = 4;
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
LOG_ERROR(RSX, "Unsupported rtt format %d", (GLenum)fmt_);
|
|
|
|
|
|
size = 4;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return size;
|
|
|
|
|
|
}
|
2017-02-13 15:22:25 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
void init_buffer()
|
|
|
|
|
|
{
|
2018-02-03 09:37:42 +01:00
|
|
|
|
const f32 resolution_scale = (context == rsx::texture_upload_context::framebuffer_storage? rsx::get_resolution_scale() : 1.f);
|
|
|
|
|
|
const u32 real_buffer_size = (resolution_scale <= 1.f) ? cpu_address_range : (u32)(resolution_scale * resolution_scale * cpu_address_range);
|
|
|
|
|
|
const u32 buffer_size = align(real_buffer_size, 4096);
|
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
if (pbo_id)
|
|
|
|
|
|
{
|
2018-02-03 09:37:42 +01:00
|
|
|
|
if (pbo_size >= buffer_size)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
glDeleteBuffers(1, &pbo_id);
|
|
|
|
|
|
pbo_id = 0;
|
|
|
|
|
|
pbo_size = 0;
|
2016-02-15 10:50:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
glGenBuffers(1, &pbo_id);
|
2017-02-27 20:39:22 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
|
|
|
|
|
|
glBufferStorage(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_MAP_READ_BIT);
|
2018-04-23 15:13:00 +02:00
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
|
2017-02-27 20:39:22 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
pbo_size = buffer_size;
|
|
|
|
|
|
}
|
2017-02-27 20:39:22 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
public:
|
2018-02-10 09:52:44 +01:00
|
|
|
|
|
2018-02-19 13:41:52 +01:00
|
|
|
|
void reset(u32 base, u32 size, bool /*flushable*/=false)
|
2017-09-08 16:52:13 +02:00
|
|
|
|
{
|
2018-09-19 00:21:57 +02:00
|
|
|
|
rsx::cached_texture_section::reset(base, size);
|
2017-02-16 19:29:56 +01:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
vram_texture = nullptr;
|
|
|
|
|
|
managed_texture.reset();
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2018-02-09 15:49:37 +01:00
|
|
|
|
|
2018-07-17 18:42:51 +02:00
|
|
|
|
void create(u16 w, u16 h, u16 depth, u16 mipmaps, gl::texture* image, u32 rsx_pitch, bool read_only,
|
2017-09-08 16:52:13 +02:00
|
|
|
|
gl::texture::format gl_format, gl::texture::type gl_type, bool swap_bytes)
|
|
|
|
|
|
{
|
2018-07-17 18:42:51 +02:00
|
|
|
|
vram_texture = static_cast<gl::viewable_image*>(image);
|
|
|
|
|
|
|
2017-11-29 15:05:36 +01:00
|
|
|
|
if (read_only)
|
|
|
|
|
|
{
|
2018-07-17 18:42:51 +02:00
|
|
|
|
managed_texture.reset(vram_texture);
|
2017-11-29 15:05:36 +01:00
|
|
|
|
aa_mode = rsx::surface_antialiasing::center_1_sample;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
if (pbo_id == 0)
|
|
|
|
|
|
init_buffer();
|
|
|
|
|
|
|
2018-06-03 13:52:21 +02:00
|
|
|
|
aa_mode = static_cast<gl::render_target*>(image)->read_aa_mode;
|
2017-11-29 15:05:36 +01:00
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
flushed = false;
|
2018-02-10 17:21:16 +01:00
|
|
|
|
synchronized = false;
|
2018-06-23 16:50:34 +02:00
|
|
|
|
sync_timestamp = 0ull;
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2018-09-10 12:22:24 +02:00
|
|
|
|
if (rsx_pitch > 0)
|
|
|
|
|
|
this->rsx_pitch = rsx_pitch;
|
|
|
|
|
|
else
|
|
|
|
|
|
this->rsx_pitch = cpu_address_range / height;
|
|
|
|
|
|
|
2017-09-18 19:22:34 +02:00
|
|
|
|
this->width = w;
|
|
|
|
|
|
this->height = h;
|
2018-06-21 17:28:53 +02:00
|
|
|
|
this->real_pitch = 0;
|
2017-09-22 15:12:10 +02:00
|
|
|
|
this->depth = depth;
|
|
|
|
|
|
this->mipmaps = mipmaps;
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
set_format(gl_format, gl_type, swap_bytes);
|
|
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2018-07-17 18:42:51 +02:00
|
|
|
|
void create_read_only(gl::viewable_image* image, u32 width, u32 height, u32 depth, u32 mipmaps)
|
2017-09-08 16:52:13 +02:00
|
|
|
|
{
|
|
|
|
|
|
//Only to be used for ro memory, we dont care about most members, just dimensions and the vram texture handle
|
2017-09-18 19:22:34 +02:00
|
|
|
|
this->width = width;
|
|
|
|
|
|
this->height = height;
|
2017-09-22 15:12:10 +02:00
|
|
|
|
this->depth = depth;
|
|
|
|
|
|
this->mipmaps = mipmaps;
|
2018-04-07 12:19:49 +02:00
|
|
|
|
|
|
|
|
|
|
managed_texture.reset(image);
|
|
|
|
|
|
vram_texture = image;
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2017-09-18 19:22:34 +02:00
|
|
|
|
rsx_pitch = 0;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
real_pitch = 0;
|
|
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2018-02-03 09:37:42 +01:00
|
|
|
|
void make_flushable()
|
|
|
|
|
|
{
|
|
|
|
|
|
//verify(HERE), pbo_id == 0;
|
|
|
|
|
|
init_buffer();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-12 14:48:31 +02:00
|
|
|
|
void set_dimensions(u32 width, u32 height, u32 /*depth*/, u32 pitch)
|
2017-09-08 16:52:13 +02:00
|
|
|
|
{
|
2017-09-18 19:22:34 +02:00
|
|
|
|
this->width = width;
|
|
|
|
|
|
this->height = height;
|
|
|
|
|
|
rsx_pitch = pitch;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2017-09-04 12:05:02 +02:00
|
|
|
|
|
2017-12-18 10:02:19 +01:00
|
|
|
|
void set_format(texture::format gl_format, texture::type gl_type, bool swap_bytes)
|
2017-09-08 16:52:13 +02:00
|
|
|
|
{
|
|
|
|
|
|
format = gl_format;
|
|
|
|
|
|
type = gl_type;
|
|
|
|
|
|
pack_unpack_swap_bytes = swap_bytes;
|
|
|
|
|
|
|
2017-11-30 19:50:19 +01:00
|
|
|
|
if (format == gl::texture::format::rgba)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case gl::texture::type::f16:
|
|
|
|
|
|
gcm_format = CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case gl::texture::type::f32:
|
|
|
|
|
|
gcm_format = CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void copy_texture(bool=false)
|
|
|
|
|
|
{
|
2018-02-03 09:37:42 +01:00
|
|
|
|
if (!pbo_id)
|
|
|
|
|
|
{
|
|
|
|
|
|
init_buffer();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-23 15:13:00 +02:00
|
|
|
|
gl::texture* target_texture = vram_texture;
|
2018-02-03 09:37:42 +01:00
|
|
|
|
if ((rsx::get_resolution_scale_percent() != 100 && context == rsx::texture_upload_context::framebuffer_storage) ||
|
2018-06-21 17:28:53 +02:00
|
|
|
|
(vram_texture->pitch() != rsx_pitch))
|
2017-09-28 20:32:00 +02:00
|
|
|
|
{
|
2017-11-29 15:05:36 +01:00
|
|
|
|
u32 real_width = width;
|
|
|
|
|
|
u32 real_height = height;
|
|
|
|
|
|
|
|
|
|
|
|
switch (aa_mode)
|
|
|
|
|
|
{
|
|
|
|
|
|
case rsx::surface_antialiasing::center_1_sample:
|
|
|
|
|
|
break;
|
|
|
|
|
|
case rsx::surface_antialiasing::diagonal_centered_2_samples:
|
|
|
|
|
|
real_width *= 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
real_width *= 2;
|
|
|
|
|
|
real_height *= 2;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2017-09-28 20:32:00 +02:00
|
|
|
|
|
|
|
|
|
|
areai src_area = { 0, 0, 0, 0 };
|
2017-10-02 15:53:27 +02:00
|
|
|
|
const areai dst_area = { 0, 0, (s32)real_width, (s32)real_height };
|
2017-09-28 20:32:00 +02:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
auto ifmt = vram_texture->get_internal_format();
|
|
|
|
|
|
src_area.x2 = vram_texture->width();
|
|
|
|
|
|
src_area.y2 = vram_texture->height();
|
2017-09-28 20:32:00 +02:00
|
|
|
|
|
2017-10-02 15:53:27 +02:00
|
|
|
|
if (src_area.x2 != dst_area.x2 || src_area.y2 != dst_area.y2)
|
|
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
if (scaled_texture)
|
2017-10-02 15:53:27 +02:00
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
auto sfmt = scaled_texture->get_internal_format();
|
|
|
|
|
|
if (scaled_texture->width() != real_width ||
|
|
|
|
|
|
scaled_texture->height() != real_height ||
|
|
|
|
|
|
sfmt != ifmt)
|
2017-10-02 15:53:27 +02:00
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
//Discard current scaled texture
|
|
|
|
|
|
scaled_texture.reset();
|
2017-10-02 15:53:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
if (!scaled_texture)
|
2017-10-02 15:53:27 +02:00
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
scaled_texture = std::make_unique<gl::texture>(GL_TEXTURE_2D, real_width, real_height, 1, 1, (GLenum)ifmt);
|
2017-10-02 15:53:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-26 20:10:25 +02:00
|
|
|
|
const bool is_depth = is_depth_texture();
|
|
|
|
|
|
const bool linear_interp = is_depth? false : true;
|
2018-04-07 17:16:52 +02:00
|
|
|
|
g_hw_blitter->scale_image(vram_texture, scaled_texture.get(), src_area, dst_area, linear_interp, is_depth, {});
|
2018-04-23 15:13:00 +02:00
|
|
|
|
target_texture = scaled_texture.get();
|
2017-10-02 15:53:27 +02:00
|
|
|
|
}
|
2017-09-28 20:32:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-10-03 13:38:00 +02:00
|
|
|
|
glGetError();
|
2018-04-23 15:13:00 +02:00
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
|
2017-10-03 13:38:00 +02:00
|
|
|
|
|
2018-04-23 15:13:00 +02:00
|
|
|
|
pixel_pack_settings pack_settings;
|
2018-04-29 08:41:51 +02:00
|
|
|
|
pack_settings.alignment(1);
|
2018-04-24 20:04:38 +02:00
|
|
|
|
|
2018-04-29 08:41:51 +02:00
|
|
|
|
//NOTE: AMD proprietary driver bug - disable swap bytes
|
2018-04-24 20:04:38 +02:00
|
|
|
|
if (!::gl::get_driver_caps().vendor_AMD)
|
|
|
|
|
|
pack_settings.swap_bytes(pack_unpack_swap_bytes);
|
|
|
|
|
|
|
2018-04-23 15:13:00 +02:00
|
|
|
|
target_texture->copy_to(nullptr, format, type, pack_settings);
|
2018-06-21 17:28:53 +02:00
|
|
|
|
real_pitch = target_texture->pitch();
|
2017-04-04 18:14:36 +02:00
|
|
|
|
|
2018-04-23 15:13:00 +02:00
|
|
|
|
if (auto error = glGetError())
|
2017-10-03 13:38:00 +02:00
|
|
|
|
{
|
2018-04-23 15:13:00 +02:00
|
|
|
|
if (error == GL_OUT_OF_MEMORY && ::gl::get_driver_caps().vendor_AMD)
|
2017-10-03 13:38:00 +02:00
|
|
|
|
{
|
2018-04-23 15:13:00 +02:00
|
|
|
|
//AMD driver bug
|
|
|
|
|
|
//Pixel transfer fails with GL_OUT_OF_MEMORY. Usually happens with float textures
|
|
|
|
|
|
//Failed operations also leak a large amount of memory
|
|
|
|
|
|
LOG_ERROR(RSX, "Memory transfer failure (AMD bug). Format=0x%x, Type=0x%x", (u32)format, (u32)type);
|
2017-10-03 13:38:00 +02:00
|
|
|
|
}
|
2018-04-23 15:13:00 +02:00
|
|
|
|
else
|
2017-10-03 13:38:00 +02:00
|
|
|
|
{
|
2018-04-23 15:13:00 +02:00
|
|
|
|
LOG_ERROR(RSX, "Memory transfer failed with error 0x%x. Format=0x%x, Type=0x%x", error, (u32)format, (u32)type);
|
2017-10-03 13:38:00 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-23 15:13:00 +02:00
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
|
2017-02-13 15:22:25 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
m_fence.reset();
|
2018-02-10 17:21:16 +01:00
|
|
|
|
synchronized = true;
|
2018-06-23 16:50:34 +02:00
|
|
|
|
sync_timestamp = get_system_time();
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2017-02-13 15:22:25 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
void fill_texture(gl::texture* tex)
|
|
|
|
|
|
{
|
2018-02-10 17:21:16 +01:00
|
|
|
|
if (!synchronized)
|
2016-02-15 10:50:14 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
//LOG_WARNING(RSX, "Request to fill texture rejected because contents were not read");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2017-02-16 19:29:56 +01:00
|
|
|
|
|
2017-09-18 19:22:34 +02:00
|
|
|
|
u32 min_width = std::min((u16)tex->width(), width);
|
|
|
|
|
|
u32 min_height = std::min((u16)tex->height(), height);
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
glBindTexture(GL_TEXTURE_2D, tex->id());
|
2017-09-08 16:52:13 +02:00
|
|
|
|
glPixelStorei(GL_UNPACK_SWAP_BYTES, pack_unpack_swap_bytes);
|
|
|
|
|
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_id);
|
2018-04-07 12:19:49 +02:00
|
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, min_width, min_height, (GLenum)format, (GLenum)type, nullptr);
|
2018-04-23 15:13:00 +02:00
|
|
|
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, GL_NONE);
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2017-02-13 15:22:25 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
bool flush()
|
|
|
|
|
|
{
|
2017-10-27 15:52:27 +02:00
|
|
|
|
if (flushed) return true; //Already written, ignore
|
|
|
|
|
|
|
2018-02-10 17:21:16 +01:00
|
|
|
|
bool result = true;
|
|
|
|
|
|
if (!synchronized)
|
2017-02-13 15:22:25 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
LOG_WARNING(RSX, "Cache miss at address 0x%X. This is gonna hurt...", cpu_address_base);
|
|
|
|
|
|
copy_texture();
|
|
|
|
|
|
|
2018-02-10 17:21:16 +01:00
|
|
|
|
if (!synchronized)
|
2016-02-15 10:50:14 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
LOG_WARNING(RSX, "Nothing to copy; Setting section to readable and moving on...");
|
|
|
|
|
|
protect(utils::protection::ro);
|
|
|
|
|
|
return false;
|
2017-02-13 15:22:25 +01:00
|
|
|
|
}
|
2018-02-10 17:21:16 +01:00
|
|
|
|
|
|
|
|
|
|
result = false;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2017-02-13 15:22:25 +01:00
|
|
|
|
|
2018-06-21 17:28:53 +02:00
|
|
|
|
verify(HERE), real_pitch > 0;
|
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
m_fence.wait_for_signal();
|
|
|
|
|
|
flushed = true;
|
2017-02-13 15:22:25 +01:00
|
|
|
|
|
2018-05-10 13:50:32 +02:00
|
|
|
|
const auto valid_range = get_confirmed_range();
|
2018-05-21 09:58:49 +02:00
|
|
|
|
void *dst = get_raw_ptr(valid_range.first, true);
|
2018-05-10 13:50:32 +02:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
|
2018-05-10 13:50:32 +02:00
|
|
|
|
void *src = glMapBufferRange(GL_PIXEL_PACK_BUFFER, valid_range.first, valid_range.second, GL_MAP_READ_BIT);
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
//throw if map failed since we'll segfault anyway
|
2018-05-10 13:50:32 +02:00
|
|
|
|
verify(HERE), src != nullptr;
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2018-02-03 09:37:42 +01:00
|
|
|
|
bool require_manual_shuffle = false;
|
|
|
|
|
|
if (pack_unpack_swap_bytes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (type == gl::texture::type::sbyte || type == gl::texture::type::ubyte)
|
|
|
|
|
|
require_manual_shuffle = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-06-21 17:28:53 +02:00
|
|
|
|
if (real_pitch >= rsx_pitch || valid_range.second <= rsx_pitch)
|
2017-09-08 16:52:13 +02:00
|
|
|
|
{
|
2018-05-10 13:50:32 +02:00
|
|
|
|
memcpy(dst, src, valid_range.second);
|
2016-02-15 10:50:14 +01:00
|
|
|
|
}
|
2017-09-08 16:52:13 +02:00
|
|
|
|
else
|
2016-02-15 10:50:14 +01:00
|
|
|
|
{
|
2018-05-24 08:20:15 +02:00
|
|
|
|
if (valid_range.second % rsx_pitch)
|
|
|
|
|
|
{
|
|
|
|
|
|
fmt::throw_exception("Unreachable" HERE);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u8 *_src = (u8*)src;
|
|
|
|
|
|
u8 *_dst = (u8*)dst;
|
|
|
|
|
|
const auto num_rows = valid_range.second / rsx_pitch;
|
|
|
|
|
|
for (u32 row = 0; row < num_rows; ++row)
|
|
|
|
|
|
{
|
|
|
|
|
|
memcpy(_dst, _src, real_pitch);
|
|
|
|
|
|
_src += real_pitch;
|
|
|
|
|
|
_dst += rsx_pitch;
|
|
|
|
|
|
}
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2018-02-03 09:37:42 +01:00
|
|
|
|
if (require_manual_shuffle)
|
|
|
|
|
|
{
|
|
|
|
|
|
//byte swapping does not work on byte types, use uint_8_8_8_8 for rgba8 instead to avoid penalty
|
2018-05-10 13:50:32 +02:00
|
|
|
|
rsx::shuffle_texel_data_wzyx<u8>(dst, rsx_pitch, width, valid_range.second / rsx_pitch);
|
2018-02-03 09:37:42 +01:00
|
|
|
|
}
|
2018-04-24 20:04:38 +02:00
|
|
|
|
else if (pack_unpack_swap_bytes && ::gl::get_driver_caps().vendor_AMD)
|
|
|
|
|
|
{
|
|
|
|
|
|
//AMD driver bug - cannot use pack_swap_bytes
|
|
|
|
|
|
//Manually byteswap texel data
|
|
|
|
|
|
switch (type)
|
|
|
|
|
|
{
|
|
|
|
|
|
case texture::type::f16:
|
|
|
|
|
|
case texture::type::sshort:
|
|
|
|
|
|
case texture::type::ushort:
|
|
|
|
|
|
case texture::type::ushort_5_6_5:
|
|
|
|
|
|
case texture::type::ushort_4_4_4_4:
|
|
|
|
|
|
case texture::type::ushort_1_5_5_5_rev:
|
|
|
|
|
|
case texture::type::ushort_5_5_5_1:
|
|
|
|
|
|
{
|
2018-05-10 13:50:32 +02:00
|
|
|
|
const u32 num_reps = valid_range.second / 2;
|
2018-04-24 20:04:38 +02:00
|
|
|
|
be_t<u16>* in = (be_t<u16>*)(dst);
|
|
|
|
|
|
u16* out = (u16*)dst;
|
|
|
|
|
|
|
|
|
|
|
|
for (u32 n = 0; n < num_reps; ++n)
|
|
|
|
|
|
{
|
|
|
|
|
|
out[n] = in[n];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case texture::type::f32:
|
|
|
|
|
|
case texture::type::sint:
|
|
|
|
|
|
case texture::type::uint:
|
|
|
|
|
|
case texture::type::uint_10_10_10_2:
|
|
|
|
|
|
case texture::type::uint_24_8:
|
|
|
|
|
|
case texture::type::uint_2_10_10_10_rev:
|
|
|
|
|
|
case texture::type::uint_8_8_8_8:
|
|
|
|
|
|
{
|
2018-05-10 13:50:32 +02:00
|
|
|
|
u32 num_reps = valid_range.second / 4;
|
2018-04-24 20:04:38 +02:00
|
|
|
|
be_t<u32>* in = (be_t<u32>*)(dst);
|
|
|
|
|
|
u32* out = (u32*)dst;
|
|
|
|
|
|
|
|
|
|
|
|
for (u32 n = 0; n < num_reps; ++n)
|
|
|
|
|
|
{
|
|
|
|
|
|
out[n] = in[n];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_ERROR(RSX, "Texture type 0x%x is not implemented " HERE, (u32)type);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-02-03 09:37:42 +01:00
|
|
|
|
|
2018-05-21 09:58:49 +02:00
|
|
|
|
flush_io(valid_range.first, valid_range.second);
|
2017-09-08 16:52:13 +02:00
|
|
|
|
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
2018-04-23 15:13:00 +02:00
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, GL_NONE);
|
2017-11-29 15:05:36 +01:00
|
|
|
|
|
2018-02-10 17:21:16 +01:00
|
|
|
|
reset_write_statistics();
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
void destroy()
|
|
|
|
|
|
{
|
2018-09-05 22:52:33 +02:00
|
|
|
|
if (!locked && pbo_id == 0 && vram_texture == nullptr && m_fence.is_empty())
|
2017-09-08 16:52:13 +02:00
|
|
|
|
//Already destroyed
|
|
|
|
|
|
return;
|
2017-02-13 15:22:25 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
if (locked)
|
|
|
|
|
|
unprotect();
|
2017-02-13 15:22:25 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
if (pbo_id == 0)
|
2017-02-13 15:22:25 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
//Read-only texture, destroy texture memory
|
2018-04-07 12:19:49 +02:00
|
|
|
|
managed_texture.reset();
|
2016-02-15 10:50:14 +01:00
|
|
|
|
}
|
2017-09-08 16:52:13 +02:00
|
|
|
|
else
|
2017-02-13 15:22:25 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
//Destroy pbo cache since vram texture is managed elsewhere
|
|
|
|
|
|
glDeleteBuffers(1, &pbo_id);
|
2018-04-07 12:19:49 +02:00
|
|
|
|
scaled_texture.reset();
|
2017-02-13 15:22:25 +01:00
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
vram_texture = nullptr;
|
2017-10-23 14:39:24 +02:00
|
|
|
|
pbo_id = 0;
|
|
|
|
|
|
pbo_size = 0;
|
|
|
|
|
|
|
2017-09-21 15:24:42 +02:00
|
|
|
|
if (!m_fence.is_empty())
|
|
|
|
|
|
m_fence.destroy();
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2018-02-09 15:49:37 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
texture::format get_format() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return format;
|
|
|
|
|
|
}
|
2018-02-09 15:49:37 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
bool exists() const
|
|
|
|
|
|
{
|
2018-09-05 22:52:33 +02:00
|
|
|
|
return vram_texture != nullptr;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2018-02-09 15:49:37 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
bool is_flushable() const
|
|
|
|
|
|
{
|
2018-07-17 18:42:51 +02:00
|
|
|
|
return (protection == utils::protection::no);
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
bool is_flushed() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return flushed;
|
|
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
bool is_synchronized() const
|
|
|
|
|
|
{
|
2018-02-10 17:21:16 +01:00
|
|
|
|
return synchronized;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2017-09-04 12:05:02 +02:00
|
|
|
|
|
2017-12-18 10:02:19 +01:00
|
|
|
|
void set_flushed(bool state)
|
2017-09-08 16:52:13 +02:00
|
|
|
|
{
|
|
|
|
|
|
flushed = state;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool is_empty() const
|
|
|
|
|
|
{
|
2018-09-05 22:52:33 +02:00
|
|
|
|
return vram_texture == nullptr;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-17 18:42:51 +02:00
|
|
|
|
gl::texture_view* get_view(u32 remap_encoding, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap)
|
2018-04-07 12:19:49 +02:00
|
|
|
|
{
|
2018-07-17 18:42:51 +02:00
|
|
|
|
return vram_texture->get_view(remap_encoding, remap);
|
2018-04-07 12:19:49 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
gl::texture* get_raw_texture() const
|
2017-09-08 16:52:13 +02:00
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
return managed_texture.get();
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-07-17 18:42:51 +02:00
|
|
|
|
gl::texture_view* get_raw_view()
|
2017-09-08 16:52:13 +02:00
|
|
|
|
{
|
2018-07-17 18:42:51 +02:00
|
|
|
|
return vram_texture->get_view(0xAAE4, rsx::default_remap_vector);
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool is_depth_texture() const
|
|
|
|
|
|
{
|
2018-07-26 20:10:25 +02:00
|
|
|
|
switch (vram_texture->get_internal_format())
|
|
|
|
|
|
{
|
|
|
|
|
|
case gl::texture::internal_format::depth16:
|
|
|
|
|
|
case gl::texture::internal_format::depth24_stencil8:
|
|
|
|
|
|
case gl::texture::internal_format::depth32f_stencil8:
|
|
|
|
|
|
return true;
|
|
|
|
|
|
default:
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool has_compatible_format(gl::texture* tex) const
|
|
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
//TODO
|
|
|
|
|
|
return (tex->get_internal_format() == vram_texture->get_internal_format());
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class texture_cache : public rsx::texture_cache<void*, cached_texture_section, gl::texture*, gl::texture_view*, gl::texture, gl::texture::format>
|
|
|
|
|
|
{
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
|
|
struct discardable_storage
|
|
|
|
|
|
{
|
|
|
|
|
|
std::unique_ptr<gl::texture> image;
|
|
|
|
|
|
std::unique_ptr<gl::texture_view> view;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
discardable_storage()
|
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
discardable_storage(std::unique_ptr<gl::texture>& tex)
|
2017-09-04 12:05:02 +02:00
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
image = std::move(tex);
|
|
|
|
|
|
}
|
2018-02-15 19:37:12 +01:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
discardable_storage(std::unique_ptr<gl::texture_view>& _view)
|
|
|
|
|
|
{
|
|
|
|
|
|
view = std::move(_view);
|
2017-09-04 12:05:02 +02:00
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
discardable_storage(std::unique_ptr<gl::texture>& tex, std::unique_ptr<gl::texture_view>& _view)
|
|
|
|
|
|
{
|
|
|
|
|
|
image = std::move(tex);
|
|
|
|
|
|
view = std::move(_view);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2018-02-09 15:49:37 +01:00
|
|
|
|
|
2017-02-13 15:22:25 +01:00
|
|
|
|
private:
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
|
|
|
|
|
blitter m_hw_blitter;
|
2018-04-07 12:19:49 +02:00
|
|
|
|
std::vector<discardable_storage> m_temporary_surfaces;
|
2017-02-16 19:29:56 +01:00
|
|
|
|
|
2018-07-17 18:42:51 +02:00
|
|
|
|
cached_texture_section& create_texture(gl::viewable_image* image, u32 texaddr, u32 texsize, u32 w, u32 h, u32 depth, u32 mipmaps)
|
2016-02-15 10:50:14 +01:00
|
|
|
|
{
|
2017-09-22 15:12:10 +02:00
|
|
|
|
cached_texture_section& tex = find_cached_texture(texaddr, texsize, true, w, h, depth);
|
2017-03-29 21:27:29 +02:00
|
|
|
|
tex.reset(texaddr, texsize, false);
|
2018-07-17 18:42:51 +02:00
|
|
|
|
tex.create_read_only(image, w, h, depth, mipmaps);
|
2017-03-29 21:27:29 +02:00
|
|
|
|
read_only_range = tex.get_min_max(read_only_range);
|
2017-09-08 16:52:13 +02:00
|
|
|
|
return tex;
|
2016-02-15 10:50:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-02-13 15:22:25 +01:00
|
|
|
|
void clear()
|
2016-02-15 10:50:14 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
for (auto &address_range : m_cache)
|
2016-02-15 10:50:14 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
auto &range_data = address_range.second;
|
|
|
|
|
|
for (auto &tex : range_data.data)
|
|
|
|
|
|
{
|
|
|
|
|
|
tex.destroy();
|
|
|
|
|
|
}
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
range_data.data.resize(0);
|
2016-02-15 10:50:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
clear_temporary_subresources();
|
|
|
|
|
|
m_unreleased_texture_objects = 0;
|
2016-02-15 10:50:14 +01:00
|
|
|
|
}
|
2018-02-09 15:49:37 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
void clear_temporary_subresources()
|
2016-02-15 10:50:14 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
m_temporary_surfaces.resize(0);
|
2017-02-13 15:22:25 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
gl::texture_view* create_temporary_subresource_impl(gl::texture* src, GLenum sized_internal_fmt, GLenum dst_type, u32 gcm_format,
|
2018-03-18 12:40:26 +01:00
|
|
|
|
u16 x, u16 y, u16 width, u16 height, const texture_channel_remap_t& remap, bool copy)
|
2017-02-16 19:29:56 +01:00
|
|
|
|
{
|
2018-02-23 20:49:59 +01:00
|
|
|
|
if (sized_internal_fmt == GL_NONE)
|
|
|
|
|
|
sized_internal_fmt = gl::get_sized_internal_format(gcm_format);
|
|
|
|
|
|
|
2018-04-13 22:59:29 +02:00
|
|
|
|
gl::texture::internal_format ifmt = static_cast<gl::texture::internal_format>(sized_internal_fmt);
|
|
|
|
|
|
if (src)
|
2017-09-19 14:46:16 +02:00
|
|
|
|
{
|
2018-04-13 22:59:29 +02:00
|
|
|
|
ifmt = src->get_internal_format();
|
|
|
|
|
|
switch (ifmt)
|
|
|
|
|
|
{
|
|
|
|
|
|
case gl::texture::internal_format::depth16:
|
|
|
|
|
|
case gl::texture::internal_format::depth24_stencil8:
|
|
|
|
|
|
case gl::texture::internal_format::depth32f_stencil8:
|
|
|
|
|
|
//HACK! Should use typeless transfer instead
|
|
|
|
|
|
sized_internal_fmt = (GLenum)ifmt;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2017-09-19 14:46:16 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
auto dst = std::make_unique<gl::texture>(dst_type, width, height, 1, 1, sized_internal_fmt);
|
2017-11-30 19:50:19 +01:00
|
|
|
|
|
2018-02-21 11:46:23 +01:00
|
|
|
|
if (copy)
|
|
|
|
|
|
{
|
|
|
|
|
|
//Empty GL_ERROR
|
|
|
|
|
|
glGetError();
|
2017-02-16 19:29:56 +01:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
glCopyImageSubData(src->id(), GL_TEXTURE_2D, 0, x, y, 0,
|
|
|
|
|
|
dst->id(), dst_type, 0, 0, 0, 0, width, height, 1);
|
2017-02-16 19:29:56 +01:00
|
|
|
|
|
2018-02-21 11:46:23 +01:00
|
|
|
|
//Check for error
|
|
|
|
|
|
if (GLenum err = glGetError())
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_WARNING(RSX, "Failed to copy image subresource with GL error 0x%X", err);
|
2018-04-07 12:19:49 +02:00
|
|
|
|
return nullptr;
|
2018-02-21 11:46:23 +01:00
|
|
|
|
}
|
2017-02-16 19:29:56 +01:00
|
|
|
|
}
|
2017-04-04 18:14:36 +02:00
|
|
|
|
|
2018-04-13 22:59:29 +02:00
|
|
|
|
std::array<GLenum, 4> swizzle;
|
|
|
|
|
|
if (!src || (GLenum)ifmt != sized_internal_fmt)
|
2018-02-23 20:49:59 +01:00
|
|
|
|
{
|
2018-04-13 22:59:29 +02:00
|
|
|
|
if (src)
|
|
|
|
|
|
{
|
|
|
|
|
|
//Format mismatch
|
|
|
|
|
|
err_once("GL format mismatch (data cast?). Sized ifmt=0x%X vs Src ifmt=0x%X", sized_internal_fmt, (GLenum)ifmt);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-02-23 20:49:59 +01:00
|
|
|
|
//Apply base component map onto the new texture if a data cast has been done
|
2018-04-07 12:19:49 +02:00
|
|
|
|
swizzle = get_component_mapping(gcm_format, rsx::texture_create_flags::default_component_order);
|
2018-03-24 12:13:11 +01:00
|
|
|
|
}
|
2018-04-13 22:59:29 +02:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
swizzle = src->get_native_component_layout();
|
|
|
|
|
|
}
|
2018-02-23 20:49:59 +01:00
|
|
|
|
|
2018-03-23 16:05:56 +01:00
|
|
|
|
if (memcmp(remap.first.data(), rsx::default_remap_vector.first.data(), 4) ||
|
|
|
|
|
|
memcmp(remap.second.data(), rsx::default_remap_vector.second.data(), 4))
|
2018-04-07 12:19:49 +02:00
|
|
|
|
swizzle = apply_swizzle_remap(swizzle, remap);
|
2018-03-18 12:40:26 +01:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
auto view = std::make_unique<gl::texture_view>(dst.get(), dst_type, sized_internal_fmt, swizzle.data());
|
|
|
|
|
|
auto result = view.get();
|
|
|
|
|
|
|
|
|
|
|
|
m_temporary_surfaces.push_back({ dst, view });
|
|
|
|
|
|
return result;
|
2017-02-16 19:29:56 +01:00
|
|
|
|
}
|
2017-12-07 13:08:11 +01:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
std::array<GLenum, 4> get_component_mapping(u32 gcm_format, rsx::texture_create_flags flags)
|
2017-12-07 13:08:11 +01:00
|
|
|
|
{
|
2018-04-22 21:08:53 +02:00
|
|
|
|
switch (gcm_format)
|
|
|
|
|
|
{
|
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT:
|
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH16:
|
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH16_FLOAT:
|
|
|
|
|
|
//Dont bother letting this propagate
|
|
|
|
|
|
return{ GL_RED, GL_RED, GL_RED, GL_RED };
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-07 13:08:11 +01:00
|
|
|
|
switch (flags)
|
|
|
|
|
|
{
|
|
|
|
|
|
case rsx::texture_create_flags::default_component_order:
|
|
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
return gl::get_swizzle_remap(gcm_format);
|
2017-12-07 13:08:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
case rsx::texture_create_flags::native_component_order:
|
|
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
return{ GL_ALPHA, GL_RED, GL_GREEN, GL_BLUE };
|
2017-12-07 13:08:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
case rsx::texture_create_flags::swapped_native_component_order:
|
|
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
return{ GL_BLUE, GL_ALPHA, GL_RED, GL_GREEN };
|
2017-12-07 13:08:11 +01:00
|
|
|
|
}
|
2018-04-07 12:19:49 +02:00
|
|
|
|
default:
|
|
|
|
|
|
fmt::throw_exception("Unknown texture create flags" HERE);
|
2017-12-07 13:08:11 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-02-09 15:49:37 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
protected:
|
2018-02-09 15:49:37 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
void free_texture_section(cached_texture_section& tex) override
|
2017-02-16 19:29:56 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
tex.destroy();
|
2017-02-16 19:29:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
gl::texture_view* create_temporary_subresource_view(void*&, gl::texture** src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h,
|
2018-03-18 12:40:26 +01:00
|
|
|
|
const texture_channel_remap_t& remap_vector) override
|
2017-02-13 15:22:25 +01:00
|
|
|
|
{
|
2018-03-18 12:40:26 +01:00
|
|
|
|
return create_temporary_subresource_impl(*src, GL_NONE, GL_TEXTURE_2D, gcm_format, x, y, w, h, remap_vector, true);
|
2016-02-15 10:50:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
gl::texture_view* create_temporary_subresource_view(void*&, gl::texture* src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h,
|
2018-03-18 12:40:26 +01:00
|
|
|
|
const texture_channel_remap_t& remap_vector) override
|
2017-08-13 23:27:19 +02:00
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
return create_temporary_subresource_impl(src, (GLenum)src->get_internal_format(),
|
|
|
|
|
|
GL_TEXTURE_2D, gcm_format, x, y, w, h, remap_vector, true);
|
2017-08-13 23:27:19 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
gl::texture_view* generate_cubemap_from_images(void*&, u32 gcm_format, u16 size, const std::vector<copy_region_descriptor>& sources, const texture_channel_remap_t& /*remap_vector*/) override
|
2017-11-02 16:54:57 +01:00
|
|
|
|
{
|
2017-11-02 19:54:19 +01:00
|
|
|
|
const GLenum ifmt = gl::get_sized_internal_format(gcm_format);
|
2018-04-07 12:19:49 +02:00
|
|
|
|
auto dst_image = std::make_unique<gl::texture>(GL_TEXTURE_CUBE_MAP, size, size, 1, 1, ifmt);
|
|
|
|
|
|
auto view = std::make_unique<gl::texture_view>(dst_image.get(), GL_TEXTURE_CUBE_MAP, ifmt);
|
2017-11-02 19:54:19 +01:00
|
|
|
|
|
|
|
|
|
|
//Empty GL_ERROR
|
|
|
|
|
|
glGetError();
|
|
|
|
|
|
|
2018-03-30 12:28:46 +02:00
|
|
|
|
for (const auto &slice : sources)
|
2017-11-02 19:54:19 +01:00
|
|
|
|
{
|
2018-03-30 12:28:46 +02:00
|
|
|
|
if (slice.src)
|
2017-11-03 13:48:27 +01:00
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
glCopyImageSubData(slice.src->id(), GL_TEXTURE_2D, 0, slice.src_x, slice.src_y, 0,
|
|
|
|
|
|
dst_image->id(), GL_TEXTURE_CUBE_MAP, 0, slice.dst_x, slice.dst_y, slice.dst_z, slice.w, slice.h, 1);
|
2018-03-30 12:28:46 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (GLenum err = glGetError())
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_WARNING(RSX, "Failed to copy image subresource with GL error 0x%X", err);
|
2018-04-07 12:19:49 +02:00
|
|
|
|
return nullptr;
|
2018-03-30 12:28:46 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
auto result = view.get();
|
|
|
|
|
|
m_temporary_surfaces.push_back({ dst_image, view });
|
|
|
|
|
|
return result;
|
2018-03-30 12:28:46 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
gl::texture_view* generate_3d_from_2d_images(void*&, u32 gcm_format, u16 width, u16 height, u16 depth, const std::vector<copy_region_descriptor>& sources, const texture_channel_remap_t& /*remap_vector*/) override
|
2018-03-30 12:28:46 +02:00
|
|
|
|
{
|
|
|
|
|
|
const GLenum ifmt = gl::get_sized_internal_format(gcm_format);
|
2018-04-07 12:19:49 +02:00
|
|
|
|
auto dst_image = std::make_unique<gl::texture>(GL_TEXTURE_3D, width, height, depth, 1, ifmt);
|
|
|
|
|
|
auto view = std::make_unique<gl::texture_view>(dst_image.get(), GL_TEXTURE_3D, ifmt);
|
2018-03-30 12:28:46 +02:00
|
|
|
|
|
|
|
|
|
|
//Empty GL_ERROR
|
|
|
|
|
|
glGetError();
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto &slice : sources)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (slice.src)
|
|
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
glCopyImageSubData(slice.src->id(), GL_TEXTURE_2D, 0, slice.src_x, slice.src_y, 0,
|
|
|
|
|
|
dst_image->id(), GL_TEXTURE_3D, 0, slice.dst_x, slice.dst_y, slice.dst_z, slice.w, slice.h, 1);
|
2017-11-03 13:48:27 +01:00
|
|
|
|
}
|
2017-11-02 19:54:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (GLenum err = glGetError())
|
|
|
|
|
|
{
|
|
|
|
|
|
LOG_WARNING(RSX, "Failed to copy image subresource with GL error 0x%X", err);
|
2018-04-07 12:19:49 +02:00
|
|
|
|
return nullptr;
|
2017-11-02 19:54:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
auto result = view.get();
|
|
|
|
|
|
m_temporary_surfaces.push_back({ dst_image, view });
|
|
|
|
|
|
return result;
|
2017-11-02 16:54:57 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
gl::texture_view* generate_atlas_from_images(void*&, u32 gcm_format, u16 width, u16 height, const std::vector<copy_region_descriptor>& sections_to_copy,
|
2018-03-18 12:40:26 +01:00
|
|
|
|
const texture_channel_remap_t& remap_vector) override
|
2018-02-21 11:46:23 +01:00
|
|
|
|
{
|
2018-04-13 22:59:29 +02:00
|
|
|
|
auto result = create_temporary_subresource_impl(nullptr, GL_NONE, GL_TEXTURE_2D, gcm_format, 0, 0, width, height, remap_vector, false);
|
2018-02-21 11:46:23 +01:00
|
|
|
|
|
|
|
|
|
|
for (const auto ®ion : sections_to_copy)
|
|
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
glCopyImageSubData(region.src->id(), GL_TEXTURE_2D, 0, region.src_x, region.src_y, 0,
|
|
|
|
|
|
result->image()->id(), GL_TEXTURE_2D, 0, region.dst_x, region.dst_y, 0, region.w, region.h, 1);
|
2018-02-21 11:46:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
void update_image_contents(void*&, gl::texture_view* dst, gl::texture* src, u16 width, u16 height) override
|
2018-02-21 11:46:23 +01:00
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
glCopyImageSubData(src->id(), GL_TEXTURE_2D, 0, 0, 0, 0,
|
|
|
|
|
|
dst->image()->id(), GL_TEXTURE_2D, 0, 0, 0, 0, width, height, 1);
|
2018-02-21 11:46:23 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-18 10:02:19 +01:00
|
|
|
|
cached_texture_section* create_new_texture(void*&, u32 rsx_address, u32 rsx_size, u16 width, u16 height, u16 depth, u16 mipmaps, u32 gcm_format,
|
2018-07-17 18:42:51 +02:00
|
|
|
|
rsx::texture_upload_context context, rsx::texture_dimension_extended type, rsx::texture_create_flags flags) override
|
2016-02-15 10:50:14 +01:00
|
|
|
|
{
|
2018-07-17 18:42:51 +02:00
|
|
|
|
auto image = gl::create_texture(gcm_format, width, height, depth, mipmaps, type);
|
|
|
|
|
|
|
|
|
|
|
|
const auto swizzle = get_component_mapping(gcm_format, flags);
|
|
|
|
|
|
image->set_native_component_layout(swizzle);
|
2017-09-14 13:37:14 +02:00
|
|
|
|
|
2018-07-17 18:42:51 +02:00
|
|
|
|
auto& cached = create_texture(image, rsx_address, rsx_size, width, height, depth, mipmaps);
|
2017-02-13 15:22:25 +01:00
|
|
|
|
cached.set_dirty(false);
|
2017-09-14 13:37:14 +02:00
|
|
|
|
cached.set_view_flags(flags);
|
2017-09-18 19:22:34 +02:00
|
|
|
|
cached.set_context(context);
|
2018-04-07 17:16:52 +02:00
|
|
|
|
cached.set_gcm_format(gcm_format);
|
2017-11-02 16:54:57 +01:00
|
|
|
|
cached.set_image_type(type);
|
2016-03-11 20:25:49 +01:00
|
|
|
|
|
2018-02-03 09:37:42 +01:00
|
|
|
|
if (context != rsx::texture_upload_context::blit_engine_dst)
|
2017-10-28 21:17:27 +02:00
|
|
|
|
{
|
2017-09-19 14:46:16 +02:00
|
|
|
|
cached.protect(utils::protection::ro);
|
2018-02-03 09:37:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
//TODO: More tests on byte order
|
|
|
|
|
|
//ARGB8+native+unswizzled is confirmed with Dark Souls II character preview
|
2018-02-10 17:21:16 +01:00
|
|
|
|
switch (gcm_format)
|
|
|
|
|
|
{
|
|
|
|
|
|
case CELL_GCM_TEXTURE_A8R8G8B8:
|
2018-02-03 09:37:42 +01:00
|
|
|
|
{
|
|
|
|
|
|
bool bgra = (flags == rsx::texture_create_flags::native_component_order);
|
2018-02-10 17:21:16 +01:00
|
|
|
|
cached.set_format(bgra ? gl::texture::format::bgra : gl::texture::format::rgba, gl::texture::type::uint_8_8_8_8, false);
|
|
|
|
|
|
break;
|
2018-02-03 09:37:42 +01:00
|
|
|
|
}
|
2018-02-10 17:21:16 +01:00
|
|
|
|
case CELL_GCM_TEXTURE_R5G6B5:
|
2018-02-03 09:37:42 +01:00
|
|
|
|
{
|
|
|
|
|
|
cached.set_format(gl::texture::format::rgb, gl::texture::type::ushort_5_6_5, true);
|
2018-02-10 17:21:16 +01:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
|
|
|
|
|
{
|
|
|
|
|
|
cached.set_format(gl::texture::format::depth_stencil, gl::texture::type::uint_24_8, true);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH16:
|
|
|
|
|
|
{
|
|
|
|
|
|
cached.set_format(gl::texture::format::depth, gl::texture::type::ushort, true);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
default:
|
|
|
|
|
|
fmt::throw_exception("Unexpected gcm format 0x%X" HERE, gcm_format);
|
2018-02-03 09:37:42 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-05-10 13:50:32 +02:00
|
|
|
|
//NOTE: Protection is handled by the caller
|
2018-02-03 09:37:42 +01:00
|
|
|
|
cached.make_flushable();
|
|
|
|
|
|
cached.set_dimensions(width, height, depth, (rsx_size / height));
|
|
|
|
|
|
no_access_range = cached.get_min_max(no_access_range);
|
2017-10-28 21:17:27 +02:00
|
|
|
|
}
|
2017-09-19 14:46:16 +02:00
|
|
|
|
|
2018-02-03 09:37:42 +01:00
|
|
|
|
update_cache_tag();
|
2017-09-08 16:52:13 +02:00
|
|
|
|
return &cached;
|
2016-02-15 10:50:14 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-18 10:02:19 +01:00
|
|
|
|
cached_texture_section* upload_image_from_cpu(void*&, u32 rsx_address, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, u32 gcm_format,
|
2018-07-17 18:42:51 +02:00
|
|
|
|
rsx::texture_upload_context context, const std::vector<rsx_subresource_layout>& subresource_layout, rsx::texture_dimension_extended type, bool input_swizzled) override
|
2016-02-15 10:50:14 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
void* unused = nullptr;
|
2017-09-18 19:22:34 +02:00
|
|
|
|
auto section = create_new_texture(unused, rsx_address, pitch * height, width, height, depth, mipmaps, gcm_format, context, type,
|
2018-07-17 18:42:51 +02:00
|
|
|
|
rsx::texture_create_flags::default_component_order);
|
2017-09-14 13:37:14 +02:00
|
|
|
|
|
2018-04-07 12:19:49 +02:00
|
|
|
|
gl::upload_texture(section->get_raw_texture()->id(), rsx_address, gcm_format, width, height, depth, mipmaps,
|
2018-07-17 18:42:51 +02:00
|
|
|
|
input_swizzled, type, subresource_layout);
|
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
return section;
|
2017-02-16 19:29:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2017-12-18 10:02:19 +01:00
|
|
|
|
void enforce_surface_creation_type(cached_texture_section& section, u32 gcm_format, rsx::texture_create_flags flags) override
|
2017-02-16 19:29:56 +01:00
|
|
|
|
{
|
2017-09-14 13:37:14 +02:00
|
|
|
|
if (flags == section.get_view_flags())
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2018-07-17 18:42:51 +02:00
|
|
|
|
const auto swizzle = get_component_mapping(gcm_format, flags);
|
2018-09-18 20:06:34 +02:00
|
|
|
|
auto image = static_cast<gl::viewable_image*>(section.get_raw_texture());
|
|
|
|
|
|
|
|
|
|
|
|
verify(HERE), image != nullptr;
|
|
|
|
|
|
image->set_native_component_layout(swizzle);
|
2017-09-14 13:37:14 +02:00
|
|
|
|
|
|
|
|
|
|
section.set_view_flags(flags);
|
2017-12-07 10:09:07 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-02-01 08:44:57 +01:00
|
|
|
|
void insert_texture_barrier(void*&, gl::texture*) override
|
2017-02-13 15:22:25 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
auto &caps = gl::get_driver_caps();
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
if (caps.ARB_texture_barrier_supported)
|
|
|
|
|
|
glTextureBarrier();
|
|
|
|
|
|
else if (caps.NV_texture_barrier_supported)
|
|
|
|
|
|
glTextureBarrierNV();
|
2017-08-07 23:54:40 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-02-23 20:49:59 +01:00
|
|
|
|
bool render_target_format_is_compatible(gl::texture* tex, u32 gcm_format) override
|
|
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
auto ifmt = tex->get_internal_format();
|
|
|
|
|
|
switch (gcm_format)
|
2018-02-23 20:49:59 +01:00
|
|
|
|
{
|
2018-04-07 12:19:49 +02:00
|
|
|
|
default:
|
|
|
|
|
|
//TODO
|
2018-05-18 22:55:37 +02:00
|
|
|
|
warn_once("Format incompatibility detected, reporting failure to force data copy (GL_INTERNAL_FORMAT=0x%X, GCM_FORMAT=0x%X)", (u32)ifmt, gcm_format);
|
2018-04-07 12:19:49 +02:00
|
|
|
|
return false;
|
|
|
|
|
|
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
|
|
|
|
|
|
return (ifmt == gl::texture::internal_format::rgba16f);
|
|
|
|
|
|
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT:
|
|
|
|
|
|
return (ifmt == gl::texture::internal_format::rgba32f);
|
|
|
|
|
|
case CELL_GCM_TEXTURE_X32_FLOAT:
|
|
|
|
|
|
return (ifmt == gl::texture::internal_format::r32f);
|
|
|
|
|
|
case CELL_GCM_TEXTURE_R5G6B5:
|
|
|
|
|
|
return (ifmt == gl::texture::internal_format::r5g6b5);
|
|
|
|
|
|
case CELL_GCM_TEXTURE_A8R8G8B8:
|
|
|
|
|
|
return (ifmt == gl::texture::internal_format::rgba8 ||
|
|
|
|
|
|
ifmt == gl::texture::internal_format::depth24_stencil8 ||
|
|
|
|
|
|
ifmt == gl::texture::internal_format::depth32f_stencil8);
|
|
|
|
|
|
case CELL_GCM_TEXTURE_B8:
|
|
|
|
|
|
return (ifmt == gl::texture::internal_format::r8);
|
|
|
|
|
|
case CELL_GCM_TEXTURE_G8B8:
|
|
|
|
|
|
return (ifmt == gl::texture::internal_format::rg8);
|
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT:
|
|
|
|
|
|
return (ifmt == gl::texture::internal_format::depth24_stencil8 ||
|
|
|
|
|
|
ifmt == gl::texture::internal_format::depth32f_stencil8 ||
|
|
|
|
|
|
ifmt == gl::texture::internal_format::depth_stencil);
|
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH16:
|
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH16_FLOAT:
|
|
|
|
|
|
return (ifmt == gl::texture::internal_format::depth16 ||
|
|
|
|
|
|
ifmt == gl::texture::internal_format::depth);
|
2018-02-23 20:49:59 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
public:
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
texture_cache() {}
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
~texture_cache() {}
|
2016-02-15 10:50:14 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
void initialize()
|
2017-02-16 19:29:56 +01:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
m_hw_blitter.init();
|
2017-09-28 20:32:00 +02:00
|
|
|
|
g_hw_blitter = &m_hw_blitter;
|
2016-02-15 10:50:14 +01:00
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
void destroy() override
|
2017-08-07 23:54:40 +02:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
clear();
|
2017-09-28 20:32:00 +02:00
|
|
|
|
g_hw_blitter = nullptr;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
m_hw_blitter.destroy();
|
2017-08-07 23:54:40 +02:00
|
|
|
|
}
|
2017-09-28 20:32:00 +02:00
|
|
|
|
|
2017-12-18 10:02:19 +01:00
|
|
|
|
bool is_depth_texture(u32 rsx_address, u32 rsx_size) override
|
2017-09-04 12:05:02 +02:00
|
|
|
|
{
|
2017-09-14 13:37:14 +02:00
|
|
|
|
reader_lock lock(m_cache_mutex);
|
|
|
|
|
|
|
2017-09-19 14:46:16 +02:00
|
|
|
|
auto found = m_cache.find(get_block_address(rsx_address));
|
2017-09-18 19:22:34 +02:00
|
|
|
|
if (found == m_cache.end())
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
2018-09-20 16:07:34 +02:00
|
|
|
|
//if (found->second.valid_count == 0)
|
|
|
|
|
|
//return false;
|
2017-09-18 19:22:34 +02:00
|
|
|
|
|
|
|
|
|
|
for (auto& tex : found->second.data)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (tex.is_dirty())
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
2018-05-10 13:50:32 +02:00
|
|
|
|
if (!tex.overlaps(rsx_address, rsx::overlap_test_bounds::full_range))
|
2017-09-19 14:46:16 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if ((rsx_address + rsx_size - tex.get_section_base()) <= tex.get_section_size())
|
|
|
|
|
|
return tex.is_depth_texture();
|
|
|
|
|
|
}
|
2017-09-04 12:05:02 +02:00
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
void on_frame_end() override
|
2017-03-29 21:27:29 +02:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
if (m_unreleased_texture_objects >= m_max_zombie_objects)
|
2017-09-04 12:05:02 +02:00
|
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
|
purge_dirty();
|
2017-09-04 12:05:02 +02:00
|
|
|
|
}
|
2018-02-09 15:49:37 +01:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
clear_temporary_subresources();
|
2017-11-03 12:16:55 +01:00
|
|
|
|
m_temporary_subresource_cache.clear();
|
2018-02-11 13:48:36 +01:00
|
|
|
|
reset_frame_statistics();
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
|
bool blit(rsx::blit_src_info& src, rsx::blit_dst_info& dst, bool linear_interpolate, gl_render_targets& m_rtts)
|
|
|
|
|
|
{
|
|
|
|
|
|
void* unused = nullptr;
|
2018-02-10 17:21:16 +01:00
|
|
|
|
auto result = upload_scaled_image(src, dst, linear_interpolate, unused, m_rtts, m_hw_blitter);
|
|
|
|
|
|
|
|
|
|
|
|
if (result.succeeded)
|
|
|
|
|
|
{
|
2018-02-12 09:26:57 +01:00
|
|
|
|
if (result.real_dst_size)
|
2018-02-10 17:21:16 +01:00
|
|
|
|
{
|
2018-02-12 09:26:57 +01:00
|
|
|
|
gl::texture::format fmt;
|
|
|
|
|
|
if (!result.is_depth)
|
|
|
|
|
|
{
|
|
|
|
|
|
fmt = dst.format == rsx::blit_engine::transfer_destination_format::a8r8g8b8 ?
|
|
|
|
|
|
gl::texture::format::bgra : gl::texture::format::rgba;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
fmt = dst.format == rsx::blit_engine::transfer_destination_format::a8r8g8b8 ?
|
|
|
|
|
|
gl::texture::format::depth_stencil : gl::texture::format::depth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
flush_if_cache_miss_likely(fmt, result.real_dst_address, result.real_dst_size);
|
2018-02-10 17:21:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
2017-09-08 16:52:13 +02:00
|
|
|
|
}
|
2016-02-15 10:50:14 +01:00
|
|
|
|
};
|
2017-04-04 18:14:36 +02:00
|
|
|
|
}
|