2016-02-15 10:50:14 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#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"
|
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-08 16:52:13 +02:00
|
|
|
extern GLenum get_sized_internal_format(u32);
|
|
|
|
|
|
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;
|
|
|
|
|
u32 pbo_id = 0;
|
|
|
|
|
u32 pbo_size = 0;
|
2017-02-13 15:22:25 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
u32 vram_texture = 0;
|
2017-02-16 19:29:56 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
bool copied = false;
|
|
|
|
|
bool flushed = false;
|
|
|
|
|
bool is_depth = false;
|
2016-02-15 10:50:14 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
texture::format format = texture::format::rgba;
|
|
|
|
|
texture::type type = texture::type::ubyte;
|
|
|
|
|
bool pack_unpack_swap_bytes = false;
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (fmt_)
|
|
|
|
|
{
|
|
|
|
|
case texture::format::red:
|
|
|
|
|
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()
|
|
|
|
|
{
|
|
|
|
|
if (pbo_id)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
const u32 buffer_size = align(cpu_address_range, 4096);
|
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
|
|
|
|
|
glBufferStorage(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_MAP_READ_BIT);
|
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:
|
2017-02-27 20:39:22 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
void reset(const u32 base, const u32 size, const bool flushable=false)
|
|
|
|
|
{
|
|
|
|
|
rsx::protection_policy policy = g_cfg.video.strict_rendering_mode ? rsx::protection_policy::protect_policy_full_range : rsx::protection_policy::protect_policy_one_page;
|
|
|
|
|
rsx::buffered_section::reset(base, size, policy);
|
2016-02-15 10:50:14 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
if (flushable)
|
|
|
|
|
init_buffer();
|
|
|
|
|
|
|
|
|
|
flushed = false;
|
|
|
|
|
copied = false;
|
|
|
|
|
is_depth = false;
|
2017-02-16 19:29:56 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
vram_texture = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void create(const u16 w, const u16 h, const u16 /*depth*/, const u16 /*mipmaps*/, void*,
|
2017-09-18 19:22:34 +02:00
|
|
|
gl::texture* image, const 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)
|
|
|
|
|
{
|
|
|
|
|
if (!read_only && pbo_id == 0)
|
|
|
|
|
init_buffer();
|
2017-03-29 21:27:29 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
flushed = false;
|
|
|
|
|
copied = false;
|
|
|
|
|
is_depth = false;
|
2017-03-29 21:27:29 +02:00
|
|
|
|
2017-09-18 19:22:34 +02:00
|
|
|
this->width = w;
|
|
|
|
|
this->height = h;
|
|
|
|
|
this->rsx_pitch = rsx_pitch;
|
2017-03-29 21:27:29 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
vram_texture = image->id();
|
|
|
|
|
set_format(gl_format, gl_type, swap_bytes);
|
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
void create_read_only(const u32 id, const u32 width, const u32 height)
|
|
|
|
|
{
|
|
|
|
|
//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-08 16:52:13 +02:00
|
|
|
vram_texture = id;
|
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
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
void set_dimensions(u32 width, u32 height, u32 pitch)
|
|
|
|
|
{
|
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
|
|
|
real_pitch = width * get_pixel_size(format, type);
|
|
|
|
|
}
|
2017-09-04 12:05:02 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
void set_format(const texture::format gl_format, const texture::type gl_type, const bool swap_bytes)
|
|
|
|
|
{
|
|
|
|
|
format = gl_format;
|
|
|
|
|
type = gl_type;
|
|
|
|
|
pack_unpack_swap_bytes = swap_bytes;
|
|
|
|
|
|
2017-09-18 19:22:34 +02:00
|
|
|
real_pitch = width * get_pixel_size(format, type);
|
2017-09-08 16:52:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void set_depth_flag(bool is_depth_fmt)
|
|
|
|
|
{
|
|
|
|
|
is_depth = is_depth_fmt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void set_source(gl::texture &source)
|
|
|
|
|
{
|
|
|
|
|
vram_texture = source.id();
|
|
|
|
|
}
|
2017-02-16 19:29:56 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
void copy_texture(bool=false)
|
|
|
|
|
{
|
|
|
|
|
if (!glIsTexture(vram_texture))
|
2017-02-16 19:29:56 +01:00
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
LOG_ERROR(RSX, "Attempted to download rtt texture, but texture handle was invalid! (0x%X)", vram_texture);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-02-16 19:29:56 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
glPixelStorei(GL_PACK_SWAP_BYTES, pack_unpack_swap_bytes);
|
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
|
2017-04-04 18:14:36 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
if (get_driver_caps().EXT_dsa_supported)
|
|
|
|
|
glGetTextureImageEXT(vram_texture, GL_TEXTURE_2D, 0, (GLenum)format, (GLenum)type, nullptr);
|
|
|
|
|
else
|
|
|
|
|
glGetTextureImage(vram_texture, 0, (GLenum)format, (GLenum)type, pbo_size, nullptr);
|
2017-04-04 18:14:36 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
2017-02-13 15:22:25 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
m_fence.reset();
|
|
|
|
|
copied = true;
|
|
|
|
|
}
|
2017-02-13 15:22:25 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
void fill_texture(gl::texture* tex)
|
|
|
|
|
{
|
|
|
|
|
if (!copied)
|
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
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
tex->bind();
|
|
|
|
|
glPixelStorei(GL_UNPACK_SWAP_BYTES, pack_unpack_swap_bytes);
|
|
|
|
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_id);
|
|
|
|
|
glTexSubImage2D((GLenum)tex->get_target(), 0, 0, 0, min_width, min_height, (GLenum)format, (GLenum)type, nullptr);
|
|
|
|
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
|
|
|
|
}
|
2017-02-13 15:22:25 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
bool flush()
|
|
|
|
|
{
|
|
|
|
|
if (!copied)
|
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();
|
|
|
|
|
|
2017-02-16 19:29:56 +01:00
|
|
|
if (!copied)
|
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
|
|
|
}
|
2017-09-08 16:52:13 +02:00
|
|
|
}
|
2017-02-13 15:22:25 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
protect(utils::protection::rw);
|
|
|
|
|
m_fence.wait_for_signal();
|
|
|
|
|
flushed = true;
|
2017-02-13 15:22:25 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
|
|
|
|
|
void *data = glMapBufferRange(GL_PIXEL_PACK_BUFFER, 0, pbo_size, GL_MAP_READ_BIT);
|
|
|
|
|
u8 *dst = vm::ps3::_ptr<u8>(cpu_address_base);
|
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
|
|
|
|
|
verify(HERE), data != nullptr;
|
2016-02-15 10:50:14 +01:00
|
|
|
|
2017-09-18 19:22:34 +02:00
|
|
|
if (real_pitch >= rsx_pitch)
|
2017-09-08 16:52:13 +02:00
|
|
|
{
|
|
|
|
|
memcpy(dst, data, cpu_address_range);
|
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
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
//TODO: Use compression hint from the gcm tile information
|
|
|
|
|
//TODO: Fall back to bilinear filtering if samples > 2
|
2017-08-07 23:54:40 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
const u8 pixel_size = get_pixel_size(format, type);
|
2017-09-18 19:22:34 +02:00
|
|
|
const u8 samples = rsx_pitch / real_pitch;
|
|
|
|
|
rsx::scale_image_nearest(dst, const_cast<const void*>(data), width, height, rsx_pitch, real_pitch, pixel_size, samples);
|
2017-09-08 16:52:13 +02:00
|
|
|
}
|
2016-02-15 10:50:14 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
|
|
|
|
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2016-02-15 10:50:14 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
void destroy()
|
|
|
|
|
{
|
|
|
|
|
if (!locked && pbo_id == 0 && vram_texture == 0 && m_fence.is_empty())
|
|
|
|
|
//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
|
|
|
|
|
glDeleteTextures(1, &vram_texture);
|
|
|
|
|
vram_texture = 0;
|
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);
|
|
|
|
|
pbo_id = 0;
|
|
|
|
|
pbo_size = 0;
|
2017-02-13 15:22:25 +01:00
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
2017-09-21 15:24:42 +02:00
|
|
|
if (!m_fence.is_empty())
|
|
|
|
|
m_fence.destroy();
|
2017-09-08 16:52:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
texture::format get_format() const
|
|
|
|
|
{
|
|
|
|
|
return format;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool exists() const
|
|
|
|
|
{
|
|
|
|
|
return vram_texture != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool is_flushable() const
|
|
|
|
|
{
|
2017-09-15 00:32:23 +02:00
|
|
|
return (locked && pbo_id != 0);
|
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
|
|
|
|
|
{
|
|
|
|
|
return copied;
|
|
|
|
|
}
|
2017-09-04 12:05:02 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
void set_flushed(const bool state)
|
|
|
|
|
{
|
|
|
|
|
flushed = state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool is_empty() const
|
|
|
|
|
{
|
|
|
|
|
return vram_texture == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 get_raw_view() const
|
|
|
|
|
{
|
|
|
|
|
return vram_texture;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 get_raw_texture() const
|
|
|
|
|
{
|
|
|
|
|
return vram_texture;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool is_depth_texture() const
|
|
|
|
|
{
|
|
|
|
|
return is_depth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool has_compatible_format(gl::texture* tex) const
|
|
|
|
|
{
|
|
|
|
|
GLenum fmt;
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, vram_texture);
|
|
|
|
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&fmt);
|
|
|
|
|
|
|
|
|
|
if (auto as_rtt = dynamic_cast<gl::render_target*>(tex))
|
2017-09-04 12:05:02 +02:00
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
return (GLenum)as_rtt->get_compatible_internal_format() == fmt;
|
2017-09-04 12:05:02 +02:00
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
return (gl::texture::format)fmt == tex->get_internal_format();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class texture_cache : public rsx::texture_cache<void*, cached_texture_section, u32, u32, gl::texture, gl::texture::format>
|
|
|
|
|
{
|
|
|
|
|
private:
|
|
|
|
|
|
2017-03-29 21:27:29 +02:00
|
|
|
class blitter
|
|
|
|
|
{
|
|
|
|
|
fbo blit_src;
|
2017-09-04 12:05:02 +02:00
|
|
|
fbo blit_dst;
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
void init()
|
|
|
|
|
{
|
|
|
|
|
blit_src.create();
|
2017-09-04 12:05:02 +02:00
|
|
|
blit_dst.create();
|
2017-03-29 21:27:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void destroy()
|
|
|
|
|
{
|
2017-09-04 12:05:02 +02:00
|
|
|
blit_dst.remove();
|
2017-03-29 21:27:29 +02:00
|
|
|
blit_src.remove();
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
u32 scale_image(u32 src, u32 dst, const areai src_rect, const areai dst_rect, bool linear_interpolation, bool is_depth_copy)
|
2017-03-29 21:27:29 +02:00
|
|
|
{
|
|
|
|
|
s32 old_fbo = 0;
|
|
|
|
|
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_fbo);
|
|
|
|
|
|
|
|
|
|
u32 dst_tex = dst;
|
|
|
|
|
filter interp = linear_interpolation ? filter::linear : filter::nearest;
|
|
|
|
|
|
2017-09-04 12:05:02 +02:00
|
|
|
GLenum attachment = is_depth_copy ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0;
|
|
|
|
|
|
|
|
|
|
blit_src.bind();
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, src, 0);
|
|
|
|
|
blit_src.check();
|
|
|
|
|
|
|
|
|
|
blit_dst.bind();
|
|
|
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, dst_tex, 0);
|
|
|
|
|
blit_dst.check();
|
|
|
|
|
|
2017-03-29 21:27:29 +02:00
|
|
|
GLboolean scissor_test_enabled = glIsEnabled(GL_SCISSOR_TEST);
|
|
|
|
|
if (scissor_test_enabled)
|
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
blit_src.blit(blit_dst, src_rect, dst_rect, is_depth_copy ? buffers::depth : buffers::color, interp);
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
|
|
|
if (scissor_test_enabled)
|
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
|
|
|
|
|
|
|
|
glBindFramebuffer(GL_FRAMEBUFFER, old_fbo);
|
|
|
|
|
return dst_tex;
|
|
|
|
|
}
|
2017-02-13 15:22:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private:
|
2017-03-29 21:27:29 +02:00
|
|
|
|
|
|
|
|
blitter m_hw_blitter;
|
2017-09-08 16:52:13 +02:00
|
|
|
std::vector<u32> m_temporary_surfaces;
|
2017-02-16 19:29:56 +01:00
|
|
|
|
2017-03-29 21:27:29 +02:00
|
|
|
cached_texture_section& create_texture(u32 id, u32 texaddr, u32 texsize, u32 w, u32 h)
|
2016-02-15 10:50:14 +01:00
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
cached_texture_section& tex = find_cached_texture(texaddr, texsize, true, w, h);
|
2017-03-29 21:27:29 +02:00
|
|
|
tex.reset(texaddr, texsize, false);
|
|
|
|
|
tex.create_read_only(id, w, h);
|
|
|
|
|
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
|
|
|
}
|
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
|
|
|
for (u32 &id : m_temporary_surfaces)
|
2017-02-13 15:22:25 +01:00
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
glDeleteTextures(1, &id);
|
2016-02-15 10:50:14 +01:00
|
|
|
}
|
2017-02-13 15:22:25 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
m_temporary_surfaces.resize(0);
|
2017-02-13 15:22:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-16 19:29:56 +01:00
|
|
|
u32 create_temporary_subresource(u32 src_id, GLenum sized_internal_fmt, u16 x, u16 y, u16 width, u16 height)
|
|
|
|
|
{
|
|
|
|
|
u32 dst_id = 0;
|
|
|
|
|
|
2017-09-19 14:46:16 +02:00
|
|
|
GLenum ifmt;
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, src_id);
|
|
|
|
|
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&ifmt);
|
|
|
|
|
|
|
|
|
|
switch (ifmt)
|
|
|
|
|
{
|
|
|
|
|
case GL_DEPTH_COMPONENT16:
|
|
|
|
|
case GL_DEPTH_COMPONENT24:
|
|
|
|
|
case GL_DEPTH24_STENCIL8:
|
|
|
|
|
sized_internal_fmt = ifmt;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-16 19:29:56 +01:00
|
|
|
glGenTextures(1, &dst_id);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, dst_id);
|
|
|
|
|
|
|
|
|
|
glTexStorage2D(GL_TEXTURE_2D, 1, sized_internal_fmt, width, height);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
|
|
|
|
|
|
|
|
//Empty GL_ERROR
|
|
|
|
|
glGetError();
|
|
|
|
|
|
|
|
|
|
glCopyImageSubData(src_id, GL_TEXTURE_2D, 0, x, y, 0,
|
|
|
|
|
dst_id, GL_TEXTURE_2D, 0, 0, 0, 0, width, height, 1);
|
|
|
|
|
|
|
|
|
|
m_temporary_surfaces.push_back(dst_id);
|
|
|
|
|
|
|
|
|
|
//Check for error
|
|
|
|
|
if (GLenum err = glGetError())
|
|
|
|
|
{
|
|
|
|
|
LOG_WARNING(RSX, "Failed to copy image subresource with GL error 0x%X", err);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2017-04-04 18:14:36 +02:00
|
|
|
|
2017-02-16 19:29:56 +01:00
|
|
|
return dst_id;
|
|
|
|
|
}
|
2017-09-08 16:52:13 +02:00
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
u32 create_temporary_subresource_view(void*&, u32* src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h) override
|
2017-02-13 15:22:25 +01:00
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
const GLenum ifmt = gl::get_sized_internal_format(gcm_format);
|
|
|
|
|
return create_temporary_subresource(*src, ifmt, x, y, w, h);
|
2016-02-15 10:50:14 +01:00
|
|
|
}
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
u32 create_temporary_subresource_view(void*&, gl::texture* src, u32 gcm_format, u16 x, u16 y, u16 w, u16 h) override
|
2017-08-13 23:27:19 +02:00
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
if (auto as_rtt = dynamic_cast<gl::render_target*>(src))
|
2017-08-13 23:27:19 +02:00
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
return create_temporary_subresource(src->id(), (GLenum)as_rtt->get_compatible_internal_format(), x, y, w, h);
|
2017-08-13 23:27:19 +02:00
|
|
|
}
|
2017-09-08 16:52:13 +02:00
|
|
|
else
|
2017-08-13 23:27:19 +02:00
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
const GLenum ifmt = gl::get_sized_internal_format(gcm_format);
|
|
|
|
|
return create_temporary_subresource(src->id(), ifmt, x, y, w, h);
|
2017-08-13 23:27:19 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
cached_texture_section* create_new_texture(void*&, u32 rsx_address, u32 rsx_size, u16 width, u16 height, u16 depth, u16 mipmaps, const u32 gcm_format,
|
2017-09-18 19:22:34 +02:00
|
|
|
const rsx::texture_upload_context context, const rsx::texture_dimension_extended type, const rsx::texture_create_flags flags,
|
|
|
|
|
std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap_vector) override
|
2016-02-15 10:50:14 +01:00
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
u32 vram_texture = gl::create_texture(gcm_format, width, height, depth, mipmaps, type);
|
|
|
|
|
bool depth_flag = false;
|
2017-02-16 19:29:56 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
switch (gcm_format)
|
2016-02-15 10:50:14 +01:00
|
|
|
{
|
2017-09-08 16:52:13 +02:00
|
|
|
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
|
|
|
|
case CELL_GCM_TEXTURE_DEPTH16:
|
|
|
|
|
depth_flag = true;
|
|
|
|
|
break;
|
2017-02-13 15:22:25 +01:00
|
|
|
}
|
2016-02-15 10:50:14 +01:00
|
|
|
|
2017-09-14 13:37:14 +02:00
|
|
|
if (flags == rsx::texture_create_flags::swapped_native_component_order)
|
|
|
|
|
{
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, vram_texture);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ALPHA);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_GREEN);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_BLUE);
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
auto& cached = create_texture(vram_texture, rsx_address, rsx_size, width, height);
|
2017-02-13 15:22:25 +01:00
|
|
|
cached.set_dirty(false);
|
2017-09-08 16:52:13 +02:00
|
|
|
cached.set_depth_flag(depth_flag);
|
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);
|
2016-03-11 20:25:49 +01:00
|
|
|
|
2017-09-19 14:46:16 +02:00
|
|
|
//Its not necessary to lock blit dst textures as they are just reused as necessary
|
|
|
|
|
if (context != rsx::texture_upload_context::blit_engine_dst || g_cfg.video.strict_rendering_mode)
|
|
|
|
|
cached.protect(utils::protection::ro);
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
return &cached;
|
2016-02-15 10:50:14 +01:00
|
|
|
}
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
cached_texture_section* upload_image_from_cpu(void*&, u32 rsx_address, u16 width, u16 height, u16 depth, u16 mipmaps, u16 pitch, const u32 gcm_format,
|
2017-09-14 13:37:14 +02:00
|
|
|
const rsx::texture_upload_context context, std::vector<rsx_subresource_layout>& subresource_layout, const rsx::texture_dimension_extended type, const bool swizzled,
|
2017-09-08 16:52:13 +02:00
|
|
|
std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap_vector) 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,
|
2017-09-08 16:52:13 +02:00
|
|
|
rsx::texture_create_flags::default_component_order, remap_vector);
|
2016-02-15 10:50:14 +01:00
|
|
|
|
2017-09-14 13:37:14 +02:00
|
|
|
//Swizzling is ignored for blit engine copy and emulated using remapping
|
|
|
|
|
bool input_swizzled = (context == rsx::texture_upload_context::blit_engine_src)? false : swizzled;
|
|
|
|
|
|
2017-09-19 14:46:16 +02:00
|
|
|
gl::upload_texture(section->get_raw_texture(), rsx_address, gcm_format, width, height, depth, mipmaps, input_swizzled, type, subresource_layout, remap_vector, false);
|
2017-09-08 16:52:13 +02:00
|
|
|
return section;
|
2017-02-16 19:29:56 +01:00
|
|
|
}
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
void enforce_surface_creation_type(cached_texture_section& section, const 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;
|
|
|
|
|
|
|
|
|
|
if (flags == rsx::texture_create_flags::swapped_native_component_order)
|
|
|
|
|
{
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, section.get_raw_texture());
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ALPHA);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_GREEN);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_BLUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
section.set_view_flags(flags);
|
2017-02-13 15:22:25 +01:00
|
|
|
}
|
2016-02-15 10:50:14 +01:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
void insert_texture_barrier() 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
|
|
|
}
|
|
|
|
|
|
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();
|
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();
|
|
|
|
|
m_hw_blitter.destroy();
|
2017-08-07 23:54:40 +02:00
|
|
|
}
|
2017-09-08 16:52:13 +02:00
|
|
|
|
2017-09-19 14:46:16 +02:00
|
|
|
bool is_depth_texture(const u32 rsx_address, const 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;
|
|
|
|
|
|
|
|
|
|
if (found->second.valid_count == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (auto& tex : found->second.data)
|
|
|
|
|
{
|
|
|
|
|
if (tex.is_dirty())
|
|
|
|
|
continue;
|
|
|
|
|
|
2017-09-19 14:46:16 +02:00
|
|
|
if (!tex.overlaps(rsx_address, true))
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
clear_temporary_subresources();
|
|
|
|
|
}
|
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;
|
|
|
|
|
return upload_scaled_image(src, dst, linear_interpolate, unused, m_rtts, m_hw_blitter);
|
|
|
|
|
}
|
2017-03-29 21:27:29 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
template<typename RsxTextureType>
|
|
|
|
|
void upload_and_bind_texture(int index, GLenum target, RsxTextureType &tex, gl_render_targets &m_rtts)
|
|
|
|
|
{
|
|
|
|
|
glActiveTexture(GL_TEXTURE0 + index);
|
|
|
|
|
void* unused = nullptr;
|
2017-03-29 21:27:29 +02:00
|
|
|
|
2017-09-08 16:52:13 +02:00
|
|
|
auto id = upload_texture(unused, tex, m_rtts);
|
|
|
|
|
glBindTexture(target, id);
|
2017-03-29 21:27:29 +02:00
|
|
|
}
|
2016-02-15 10:50:14 +01:00
|
|
|
};
|
2017-04-04 18:14:36 +02:00
|
|
|
}
|