rasterizer_cache: Remove shared_ptr usage

* Switches to yuzu's slot vector for improved memory locality.
This commit is contained in:
GPUCode
2023-04-26 21:35:19 +03:00
parent cba8a2a18e
commit 41b777a693
13 changed files with 563 additions and 535 deletions

View File

@@ -13,6 +13,7 @@
#include "core/frontend/image_interface.h" #include "core/frontend/image_interface.h"
#include "video_core/custom_textures/custom_tex_manager.h" #include "video_core/custom_textures/custom_tex_manager.h"
#include "video_core/rasterizer_cache/surface_params.h" #include "video_core/rasterizer_cache/surface_params.h"
#include "video_core/rasterizer_cache/utils.h"
namespace VideoCore { namespace VideoCore {

View File

@@ -10,9 +10,9 @@ namespace VideoCore {
FramebufferBase::FramebufferBase() = default; FramebufferBase::FramebufferBase() = default;
FramebufferBase::FramebufferBase(const Pica::Regs& regs, const SurfaceBase* const color, FramebufferBase::FramebufferBase(const Pica::Regs& regs, const SurfaceBase* color, u32 color_level,
u32 color_level, const SurfaceBase* const depth_stencil, const SurfaceBase* depth_stencil, u32 depth_level,
u32 depth_level, Common::Rectangle<u32> surfaces_rect) { Common::Rectangle<u32> surfaces_rect) {
res_scale = color ? color->res_scale : (depth_stencil ? depth_stencil->res_scale : 1u); res_scale = color ? color->res_scale : (depth_stencil ? depth_stencil->res_scale : 1u);
// Determine the draw rectangle (render area + scissor) // Determine the draw rectangle (render area + scissor)

View File

@@ -29,8 +29,8 @@ struct ViewportInfo {
class FramebufferBase { class FramebufferBase {
public: public:
FramebufferBase(); FramebufferBase();
FramebufferBase(const Pica::Regs& regs, const SurfaceBase* const color, u32 color_level, FramebufferBase(const Pica::Regs& regs, const SurfaceBase* color, u32 color_level,
const SurfaceBase* const depth_stencil, u32 depth_level, const SurfaceBase* depth_stencil, u32 depth_level,
Common::Rectangle<u32> surfaces_rect); Common::Rectangle<u32> surfaces_rect);
SurfaceParams ColorParams() const noexcept { SurfaceParams ColorParams() const noexcept {
@@ -66,6 +66,7 @@ protected:
switch (type) { switch (type) {
case VideoCore::SurfaceType::Color: case VideoCore::SurfaceType::Color:
return 0; return 0;
case VideoCore::SurfaceType::Depth:
case VideoCore::SurfaceType::DepthStencil: case VideoCore::SurfaceType::DepthStencil:
return 1; return 1;
default: default:

File diff suppressed because it is too large Load Diff

View File

@@ -51,32 +51,32 @@ class RasterizerCache {
/// Address shift for caching surfaces into a hash table /// Address shift for caching surfaces into a hash table
static constexpr u64 CITRA_PAGEBITS = 18; static constexpr u64 CITRA_PAGEBITS = 18;
using TextureRuntime = typename T::TextureRuntime; using Runtime = typename T::Runtime;
using Sampler = typename T::Sampler; using Sampler = typename T::Sampler;
using SurfaceRef = std::shared_ptr<typename T::Surface>; using Surface = typename T::Surface;
using Framebuffer = typename T::Framebuffer; using Framebuffer = typename T::Framebuffer;
using SurfaceMap = boost::icl::interval_map<PAddr, SurfaceRef, boost::icl::partial_absorber, using SurfaceMap = boost::icl::interval_map<PAddr, SurfaceId, boost::icl::partial_absorber,
std::less, boost::icl::inplace_plus, std::less, boost::icl::inplace_plus,
boost::icl::inter_section, SurfaceInterval>; boost::icl::inter_section, SurfaceInterval>;
using SurfaceRect_Tuple = std::tuple<SurfaceRef, Common::Rectangle<u32>>; using SurfaceRect_Tuple = std::pair<SurfaceId, Common::Rectangle<u32>>;
using PageMap = boost::icl::interval_map<u32, int>; using PageMap = boost::icl::interval_map<u32, int>;
struct RenderTargets { struct RenderTargets {
SurfaceRef color_surface; SurfaceId color_id;
SurfaceRef depth_surface; SurfaceId depth_id;
}; };
struct TextureCube { struct TextureCube {
SurfaceRef surface{}; SurfaceId surface_id;
std::array<SurfaceRef, 6> faces{}; std::array<SurfaceId, 6> face_ids;
std::array<u64, 6> ticks{}; std::array<u64, 6> ticks;
}; };
public: public:
explicit RasterizerCache(Memory::MemorySystem& memory, CustomTexManager& custom_tex_manager, explicit RasterizerCache(Memory::MemorySystem& memory, CustomTexManager& custom_tex_manager,
TextureRuntime& runtime, Pica::Regs& regs, RendererBase& renderer); Runtime& runtime, Pica::Regs& regs, RendererBase& renderer);
~RasterizerCache(); ~RasterizerCache();
/// Notify the cache that a new frame has been queued /// Notify the cache that a new frame has been queued
@@ -91,17 +91,19 @@ public:
/// Perform hardware accelerated memory fill according to the provided configuration /// Perform hardware accelerated memory fill according to the provided configuration
bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config); bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config);
/// Returns a reference to the surface object assigned to surface_id
Surface& GetSurface(SurfaceId surface_id);
/// Returns a reference to the sampler object matching the provided configuration /// Returns a reference to the sampler object matching the provided configuration
Sampler& GetSampler(const Pica::TexturingRegs::TextureConfig& config); Sampler& GetSampler(const Pica::TexturingRegs::TextureConfig& config);
Sampler& GetSampler(SamplerId sampler_id); Sampler& GetSampler(SamplerId sampler_id);
/// Copy one surface's region to another /// Copy one surface's region to another
void CopySurface(const SurfaceRef& src_surface, const SurfaceRef& dst_surface, void CopySurface(Surface& src_surface, Surface& dst_surface, SurfaceInterval copy_interval);
SurfaceInterval copy_interval);
/// Load a texture from 3DS memory to OpenGL and cache it (if not already cached) /// Load a texture from 3DS memory to OpenGL and cache it (if not already cached)
SurfaceRef GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale, SurfaceId GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale,
bool load_if_create); bool load_if_create);
/// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from /// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from
/// 3DS memory to OpenGL and caches it (if not already cached) /// 3DS memory to OpenGL and caches it (if not already cached)
@@ -109,11 +111,11 @@ public:
bool load_if_create); bool load_if_create);
/// Get a surface based on the texture configuration /// Get a surface based on the texture configuration
SurfaceRef GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config); Surface& GetTextureSurface(const Pica::TexturingRegs::FullTextureConfig& config);
SurfaceRef GetTextureSurface(const Pica::Texture::TextureInfo& info, u32 max_level = 0); SurfaceId GetTextureSurface(const Pica::Texture::TextureInfo& info, u32 max_level = 0);
/// Get a texture cube based on the texture configuration /// Get a texture cube based on the texture configuration
SurfaceRef GetTextureCube(const TextureCubeConfig& config); Surface& GetTextureCube(const TextureCubeConfig& config);
/// Get the color and depth surfaces based on the framebuffer configuration /// Get the color and depth surfaces based on the framebuffer configuration
Framebuffer GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb); Framebuffer GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb);
@@ -125,10 +127,10 @@ public:
SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params); SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params);
/// Write any cached resources overlapping the region back to memory (if dirty) /// Write any cached resources overlapping the region back to memory (if dirty)
void FlushRegion(PAddr addr, u32 size, SurfaceRef flush_surface = nullptr); void FlushRegion(PAddr addr, u32 size, SurfaceId flush_surface = {});
/// Mark region as being invalidated by region_owner (nullptr if 3DS memory) /// Mark region as being invalidated by region_owner (nullptr if 3DS memory)
void InvalidateRegion(PAddr addr, u32 size, const SurfaceRef& region_owner); void InvalidateRegion(PAddr addr, u32 size, SurfaceId region_owner = {});
/// Flush all cached resources tracked by this cache manager /// Flush all cached resources tracked by this cache manager
void FlushAll(); void FlushAll();
@@ -159,33 +161,29 @@ private:
/// Get the best surface match (and its match type) for the given flags /// Get the best surface match (and its match type) for the given flags
template <MatchFlags find_flags> template <MatchFlags find_flags>
SurfaceRef FindMatch(const SurfaceParams& params, ScaleMatch match_scale_type, SurfaceId FindMatch(const SurfaceParams& params, ScaleMatch match_scale_type,
std::optional<SurfaceInterval> validate_interval = std::nullopt); std::optional<SurfaceInterval> validate_interval = std::nullopt);
/// Transfers ownership of a memory region from src_surface to dest_surface /// Transfers ownership of a memory region from src_surface to dest_surface
void DuplicateSurface(const SurfaceRef& src_surface, const SurfaceRef& dest_surface); void DuplicateSurface(SurfaceId src_id, SurfaceId dst_id);
/// Update surface's texture for given region when necessary /// Update surface's texture for given region when necessary
void ValidateSurface(const SurfaceRef& surface, PAddr addr, u32 size); void ValidateSurface(SurfaceId surface, PAddr addr, u32 size);
/// Copies pixel data in interval from the guest VRAM to the host GPU surface /// Copies pixel data in interval from the guest VRAM to the host GPU surface
void UploadSurface(const SurfaceRef& surface, SurfaceInterval interval); void UploadSurface(Surface& surface, SurfaceInterval interval);
/// Uploads a custom texture identified with hash to the target surface /// Uploads a custom texture identified with hash to the target surface
bool UploadCustomSurface(const SurfaceRef& surface, const SurfaceParams& load_info, u64 hash); bool UploadCustomSurface(SurfaceId surface_id, SurfaceInterval interval);
/// Returns the hash used to lookup the custom surface.
u64 ComputeCustomHash(const SurfaceParams& load_info, std::span<u8> decoded,
std::span<u8> upload_data);
/// Copies pixel data in interval from the host GPU surface to the guest VRAM /// Copies pixel data in interval from the host GPU surface to the guest VRAM
void DownloadSurface(const SurfaceRef& surface, SurfaceInterval interval); void DownloadSurface(Surface& surface, SurfaceInterval interval);
/// Downloads a fill surface to guest VRAM /// Downloads a fill surface to guest VRAM
void DownloadFillSurface(const SurfaceRef& surface, SurfaceInterval interval); void DownloadFillSurface(Surface& surface, SurfaceInterval interval);
/// Returns false if there is a surface in the cache at the interval with the same bit-width, /// Returns false if there is a surface in the cache at the interval with the same bit-width,
bool NoUnimplementedReinterpretations(const SurfaceRef& surface, SurfaceParams params, bool NoUnimplementedReinterpretations(const Surface& surface, SurfaceParams params,
const SurfaceInterval& interval); const SurfaceInterval& interval);
/// Return true if a surface with an invalid pixel format exists at the interval /// Return true if a surface with an invalid pixel format exists at the interval
@@ -193,17 +191,17 @@ private:
const SurfaceInterval& interval); const SurfaceInterval& interval);
/// Attempt to find a reinterpretable surface in the cache and use it to copy for validation /// Attempt to find a reinterpretable surface in the cache and use it to copy for validation
bool ValidateByReinterpretation(const SurfaceRef& surface, SurfaceParams params, bool ValidateByReinterpretation(Surface& surface, SurfaceParams params,
const SurfaceInterval& interval); const SurfaceInterval& interval);
/// Create a new surface /// Create a new surface
SurfaceRef CreateSurface(const SurfaceParams& params); SurfaceId CreateSurface(const SurfaceParams& params);
/// Register surface into the cache /// Register surface into the cache
void RegisterSurface(const SurfaceRef& surface); void RegisterSurface(SurfaceId surface);
/// Remove surface from the cache /// Remove surface from the cache
void UnregisterSurface(const SurfaceRef& surface); void UnregisterSurface(SurfaceId surface);
/// Unregisters all surfaces from the cache /// Unregisters all surfaces from the cache
void UnregisterAll(); void UnregisterAll();
@@ -214,16 +212,17 @@ private:
private: private:
Memory::MemorySystem& memory; Memory::MemorySystem& memory;
CustomTexManager& custom_tex_manager; CustomTexManager& custom_tex_manager;
TextureRuntime& runtime; Runtime& runtime;
Pica::Regs& regs; Pica::Regs& regs;
RendererBase& renderer; RendererBase& renderer;
std::unordered_map<TextureCubeConfig, TextureCube> texture_cube_cache; std::unordered_map<TextureCubeConfig, TextureCube> texture_cube_cache;
tsl::robin_pg_map<u64, std::vector<SurfaceRef>, Common::IdentityHash<u64>> page_table; tsl::robin_pg_map<u64, std::vector<SurfaceId>, Common::IdentityHash<u64>> page_table;
std::unordered_map<SamplerParams, SamplerId> samplers; std::unordered_map<SamplerParams, SamplerId> samplers;
SlotVector<Surface> slot_surfaces;
SlotVector<Sampler> slot_samplers; SlotVector<Sampler> slot_samplers;
SurfaceMap dirty_regions; SurfaceMap dirty_regions;
PageMap cached_pages; PageMap cached_pages;
std::vector<SurfaceRef> remove_surfaces; std::vector<SurfaceId> remove_surfaces;
u32 resolution_scale_factor; u32 resolution_scale_factor;
RenderTargets render_targets; RenderTargets render_targets;
bool use_filter; bool use_filter;

View File

@@ -4,6 +4,7 @@
#pragma once #pragma once
#include <compare>
#include "common/hash.h" #include "common/hash.h"
#include "video_core/regs_texturing.h" #include "video_core/regs_texturing.h"

View File

@@ -29,60 +29,6 @@ struct SlotId {
template <class T> template <class T>
class SlotVector { class SlotVector {
public: public:
class Iterator {
friend SlotVector<T>;
public:
constexpr Iterator() = default;
Iterator& operator++() noexcept {
const u64* const bitset = slot_vector->stored_bitset.data();
const u32 size = static_cast<u32>(slot_vector->stored_bitset.size()) * 64;
if (id.index < size) {
do {
++id.index;
} while (id.index < size && !IsValid(bitset));
if (id.index == size) {
id.index = SlotId::INVALID_INDEX;
}
}
return *this;
}
Iterator operator++(int) noexcept {
const Iterator copy{*this};
++*this;
return copy;
}
bool operator==(const Iterator& other) const noexcept {
return id.index == other.id.index;
}
bool operator!=(const Iterator& other) const noexcept {
return id.index != other.id.index;
}
std::pair<SlotId, T*> operator*() const noexcept {
return {id, std::addressof((*slot_vector)[id])};
}
T* operator->() const noexcept {
return std::addressof((*slot_vector)[id]);
}
private:
Iterator(SlotVector<T>* slot_vector_, SlotId id_) noexcept
: slot_vector{slot_vector_}, id{id_} {}
bool IsValid(const u64* bitset) const noexcept {
return ((bitset[id.index / 64] >> (id.index % 64)) & 1) != 0;
}
SlotVector<T>* slot_vector;
SlotId id;
};
~SlotVector() noexcept { ~SlotVector() noexcept {
size_t index = 0; size_t index = 0;
for (u64 bits : stored_bitset) { for (u64 bits : stored_bitset) {
@@ -121,21 +67,6 @@ public:
ResetStorageBit(id.index); ResetStorageBit(id.index);
} }
[[nodiscard]] Iterator begin() noexcept {
const auto it = std::find_if(stored_bitset.begin(), stored_bitset.end(),
[](u64 value) { return value != 0; });
if (it == stored_bitset.end()) {
return end();
}
const u32 word_index = static_cast<u32>(std::distance(it, stored_bitset.begin()));
const SlotId first_id{word_index * 64 + static_cast<u32>(std::countr_zero(*it))};
return Iterator(this, first_id);
}
[[nodiscard]] Iterator end() noexcept {
return Iterator(this, SlotId{SlotId::INVALID_INDEX});
}
private: private:
struct NonTrivialDummy { struct NonTrivialDummy {
NonTrivialDummy() noexcept {} NonTrivialDummy() noexcept {}

View File

@@ -13,6 +13,14 @@ using SurfaceRegions = boost::icl::interval_set<PAddr, std::less, SurfaceInterva
struct Material; struct Material;
enum class SurfaceFlagBits : u32 {
Registered = 1 << 0, ///< Surface is registed in the rasterizer cache.
Picked = 1 << 1, ///< Surface has been picked when searching for a match.
Tracked = 1 << 2, ///< Surface is part of a texture cube and should be tracked.
Custom = 1 << 3, ///< Surface texture has been replaced with a custom texture.
};
DECLARE_ENUM_FLAG_OPERATORS(SurfaceFlagBits);
class SurfaceBase : public SurfaceParams { class SurfaceBase : public SurfaceParams {
public: public:
SurfaceBase(const SurfaceParams& params); SurfaceBase(const SurfaceParams& params);
@@ -43,7 +51,7 @@ public:
} }
bool IsCustom() const noexcept { bool IsCustom() const noexcept {
return is_custom && custom_format != CustomPixelFormat::Invalid; return True(flags & SurfaceFlagBits::Custom) && custom_format != CustomPixelFormat::Invalid;
} }
bool IsRegionValid(SurfaceInterval interval) const { bool IsRegionValid(SurfaceInterval interval) const {
@@ -70,9 +78,7 @@ private:
std::array<u8, 4> MakeFillBuffer(PAddr copy_addr); std::array<u8, 4> MakeFillBuffer(PAddr copy_addr);
public: public:
bool registered = false; SurfaceFlagBits flags{};
bool picked = false;
bool is_custom = false;
const Material* material = nullptr; const Material* material = nullptr;
SurfaceRegions invalid_regions; SurfaceRegions invalid_regions;
u32 fill_size = 0; u32 fill_size = 0;

View File

@@ -11,7 +11,7 @@ bool SurfaceParams::ExactMatch(const SurfaceParams& other_surface) const {
return std::tie(other_surface.addr, other_surface.width, other_surface.height, return std::tie(other_surface.addr, other_surface.width, other_surface.height,
other_surface.stride, other_surface.pixel_format, other_surface.is_tiled) == other_surface.stride, other_surface.pixel_format, other_surface.is_tiled) ==
std::tie(addr, width, height, stride, pixel_format, is_tiled) && std::tie(addr, width, height, stride, pixel_format, is_tiled) &&
pixel_format != PixelFormat::Invalid && levels >= other_surface.levels; pixel_format != PixelFormat::Invalid /*&& levels >= other_surface.levels*/;
} }
bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const { bool SurfaceParams::CanSubRect(const SurfaceParams& sub_surface) const {

View File

@@ -17,8 +17,13 @@ namespace VideoCore {
using SurfaceInterval = boost::icl::right_open_interval<PAddr>; using SurfaceInterval = boost::icl::right_open_interval<PAddr>;
using SurfaceId = SlotId;
using SamplerId = SlotId; using SamplerId = SlotId;
/// Fake surface ID for null surfaces
constexpr SurfaceId NULL_SURFACE_ID{0};
/// Fake surface ID for null cube surfaces
constexpr SurfaceId NULL_SURFACE_CUBE_ID{1};
/// Fake sampler ID for null samplers /// Fake sampler ID for null samplers
constexpr SamplerId NULL_SAMPLER_ID{0}; constexpr SamplerId NULL_SAMPLER_ID{0};
@@ -77,9 +82,9 @@ struct BufferTextureCopy {
}; };
struct StagingData { struct StagingData {
u32 size = 0; u32 size;
std::span<u8> mapped{}; std::span<u8> mapped;
u64 buffer_offset = 0; u64 buffer_offset;
}; };
struct TextureCubeConfig { struct TextureCubeConfig {

View File

@@ -25,7 +25,7 @@ MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(255, 128,
MICROPROFILE_DEFINE(OpenGL_VS, "OpenGL", "Vertex Shader Setup", MP_RGB(192, 128, 128)); MICROPROFILE_DEFINE(OpenGL_VS, "OpenGL", "Vertex Shader Setup", MP_RGB(192, 128, 128));
MICROPROFILE_DEFINE(OpenGL_GS, "OpenGL", "Geometry Shader Setup", MP_RGB(128, 192, 128)); MICROPROFILE_DEFINE(OpenGL_GS, "OpenGL", "Geometry Shader Setup", MP_RGB(128, 192, 128));
MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192)); MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100)); MICROPROFILE_DEFINE(OpenGL_Display, "OpenGL", "Display", MP_RGB(128, 128, 192));
using VideoCore::SurfaceType; using VideoCore::SurfaceType;
@@ -241,14 +241,14 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset,
} }
} }
PAddr data_addr = const PAddr data_addr =
base_address + loader.data_offset + (vs_input_index_min * loader.byte_count); base_address + loader.data_offset + (vs_input_index_min * loader.byte_count);
u32 vertex_num = vs_input_index_max - vs_input_index_min + 1; const u32 vertex_num = vs_input_index_max - vs_input_index_min + 1;
u32 data_size = loader.byte_count * vertex_num; const u32 data_size = loader.byte_count * vertex_num;
res_cache.FlushRegion(data_addr, data_size, nullptr); res_cache.FlushRegion(data_addr, data_size);
std::memcpy(array_ptr, VideoCore::g_memory->GetPhysicalPointer(data_addr), data_size); std::memcpy(array_ptr, memory.GetPhysicalPointer(data_addr), data_size);
array_ptr += data_size; array_ptr += data_size;
buffer_offset += data_size; buffer_offset += data_size;
@@ -277,8 +277,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset,
bool RasterizerOpenGL::SetupVertexShader() { bool RasterizerOpenGL::SetupVertexShader() {
MICROPROFILE_SCOPE(OpenGL_VS); MICROPROFILE_SCOPE(OpenGL_VS);
return shader_program_manager->UseProgrammableVertexShader(Pica::g_state.regs, return shader_program_manager->UseProgrammableVertexShader(regs, Pica::g_state.vs);
Pica::g_state.vs);
} }
bool RasterizerOpenGL::SetupGeometryShader() { bool RasterizerOpenGL::SetupGeometryShader() {
@@ -510,8 +509,8 @@ void RasterizerOpenGL::SyncTextureUnits(const Framebuffer& framebuffer) {
if (texture_index == 0) { if (texture_index == 0) {
switch (texture.config.type.Value()) { switch (texture.config.type.Value()) {
case TextureType::Shadow2D: { case TextureType::Shadow2D: {
auto surface = res_cache.GetTextureSurface(texture); Surface& surface = res_cache.GetTextureSurface(texture);
state.image_shadow_texture_px = surface->Handle(); state.image_shadow_texture_px = surface.Handle();
continue; continue;
} }
case TextureType::ShadowCube: { case TextureType::ShadowCube: {
@@ -528,23 +527,14 @@ void RasterizerOpenGL::SyncTextureUnits(const Framebuffer& framebuffer) {
} }
// Sync texture unit sampler // Sync texture unit sampler
const Sampler& sampler = res_cache.GetSampler(texture.config); Sampler& sampler = res_cache.GetSampler(texture.config);
state.texture_units[texture_index].sampler = sampler.Handle(); state.texture_units[texture_index].sampler = sampler.Handle();
// Bind the texture provided by the rasterizer cache // Bind the texture provided by the rasterizer cache
auto surface = res_cache.GetTextureSurface(texture); Surface& surface = res_cache.GetTextureSurface(texture);
if (!surface) { if (!IsFeedbackLoop(texture_index, framebuffer, surface)) {
// Can occur when texture addr is null or its memory is unmapped/invalid BindMaterial(texture_index, surface);
// HACK: In this case, the correct behaviour for the PICA is to use the last state.texture_units[texture_index].texture_2d = surface.Handle();
// rendered colour. But because this would be impractical to implement, the
// next best alternative is to use a clear texture, essentially skipping
// the geometry in question.
// For example: a bug in Pokemon X/Y causes NULL-texture squares to be drawn
// on the male character's face, which in the OpenGL default appear black.
state.texture_units[texture_index].texture_2d = default_texture;
} else if (!IsFeedbackLoop(texture_index, framebuffer, *surface)) {
BindMaterial(texture_index, *surface);
state.texture_units[texture_index].texture_2d = surface->Handle();
} }
} }
} }
@@ -561,8 +551,9 @@ void RasterizerOpenGL::BindShadowCube(const Pica::TexturingRegs::FullTextureConf
const u32 binding = static_cast<u32>(face); const u32 binding = static_cast<u32>(face);
info.physical_address = regs.texturing.GetCubePhysicalAddress(face); info.physical_address = regs.texturing.GetCubePhysicalAddress(face);
auto surface = res_cache.GetTextureSurface(info); VideoCore::SurfaceId surface_id = res_cache.GetTextureSurface(info);
state.image_shadow_texture[binding] = surface->Handle(); Surface& surface = res_cache.GetSurface(surface_id);
state.image_shadow_texture[binding] = surface.Handle();
} }
} }
@@ -580,10 +571,10 @@ void RasterizerOpenGL::BindTextureCube(const Pica::TexturingRegs::FullTextureCon
.format = texture.format, .format = texture.format,
}; };
auto surface = res_cache.GetTextureCube(config); Surface& surface = res_cache.GetTextureCube(config);
Sampler& sampler = res_cache.GetSampler(texture.config); Sampler& sampler = res_cache.GetSampler(texture.config);
state.texture_cube_unit.texture_cube = surface->Handle(); state.texture_cube_unit.texture_cube = surface.Handle();
state.texture_cube_unit.sampler = sampler.Handle(); state.texture_cube_unit.sampler = sampler.Handle();
state.texture_units[0].texture_2d = 0; state.texture_units[0].texture_2d = 0;
} }
@@ -718,24 +709,20 @@ void RasterizerOpenGL::NotifyFixedFunctionPicaRegisterChanged(u32 id) {
} }
void RasterizerOpenGL::FlushAll() { void RasterizerOpenGL::FlushAll() {
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
res_cache.FlushAll(); res_cache.FlushAll();
} }
void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) { void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) {
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
res_cache.FlushRegion(addr, size); res_cache.FlushRegion(addr, size);
} }
void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) { void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) {
MICROPROFILE_SCOPE(OpenGL_CacheManagement); res_cache.InvalidateRegion(addr, size);
res_cache.InvalidateRegion(addr, size, nullptr);
} }
void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) { void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
MICROPROFILE_SCOPE(OpenGL_CacheManagement);
res_cache.FlushRegion(addr, size); res_cache.FlushRegion(addr, size);
res_cache.InvalidateRegion(addr, size, nullptr); res_cache.InvalidateRegion(addr, size);
} }
void RasterizerOpenGL::ClearAll(bool flush) { void RasterizerOpenGL::ClearAll(bool flush) {
@@ -760,7 +747,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
if (framebuffer_addr == 0) { if (framebuffer_addr == 0) {
return false; return false;
} }
MICROPROFILE_SCOPE(OpenGL_CacheManagement); MICROPROFILE_SCOPE(OpenGL_Display);
VideoCore::SurfaceParams src_params; VideoCore::SurfaceParams src_params;
src_params.addr = framebuffer_addr; src_params.addr = framebuffer_addr;
@@ -771,27 +758,27 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
src_params.pixel_format = VideoCore::PixelFormatFromGPUPixelFormat(config.color_format); src_params.pixel_format = VideoCore::PixelFormatFromGPUPixelFormat(config.color_format);
src_params.UpdateParams(); src_params.UpdateParams();
auto [src_surface, src_rect] = const auto [src_surface_id, src_rect] =
res_cache.GetSurfaceSubRect(src_params, VideoCore::ScaleMatch::Ignore, true); res_cache.GetSurfaceSubRect(src_params, VideoCore::ScaleMatch::Ignore, true);
if (!src_surface_id) {
if (src_surface == nullptr) {
return false; return false;
} }
const u32 scaled_width = src_surface->GetScaledWidth(); const Surface& src_surface = res_cache.GetSurface(src_surface_id);
const u32 scaled_height = src_surface->GetScaledHeight(); const u32 scaled_width = src_surface.GetScaledWidth();
const u32 scaled_height = src_surface.GetScaledHeight();
screen_info.display_texcoords = Common::Rectangle<float>( screen_info.display_texcoords = Common::Rectangle<float>(
(float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width, (float)src_rect.bottom / (float)scaled_height, (float)src_rect.left / (float)scaled_width,
(float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width); (float)src_rect.top / (float)scaled_height, (float)src_rect.right / (float)scaled_width);
screen_info.display_texture = src_surface->Handle(); screen_info.display_texture = src_surface.Handle();
return true; return true;
} }
void RasterizerOpenGL::SyncClipEnabled() { void RasterizerOpenGL::SyncClipEnabled() {
state.clip_distance[1] = Pica::g_state.regs.rasterizer.clip_enable != 0; state.clip_distance[1] = regs.rasterizer.clip_enable != 0;
} }
void RasterizerOpenGL::SyncCullMode() { void RasterizerOpenGL::SyncCullMode() {
@@ -819,7 +806,7 @@ void RasterizerOpenGL::SyncCullMode() {
} }
void RasterizerOpenGL::SyncBlendEnabled() { void RasterizerOpenGL::SyncBlendEnabled() {
state.blend.enabled = (Pica::g_state.regs.framebuffer.output_merger.alphablend_enable == 1); state.blend.enabled = (regs.framebuffer.output_merger.alphablend_enable == 1);
} }
void RasterizerOpenGL::SyncBlendFuncs() { void RasterizerOpenGL::SyncBlendFuncs() {
@@ -838,8 +825,7 @@ void RasterizerOpenGL::SyncBlendFuncs() {
} }
void RasterizerOpenGL::SyncBlendColor() { void RasterizerOpenGL::SyncBlendColor() {
auto blend_color = auto blend_color = PicaToGL::ColorRGBA8(regs.framebuffer.output_merger.blend_const.raw);
PicaToGL::ColorRGBA8(Pica::g_state.regs.framebuffer.output_merger.blend_const.raw);
state.blend.color.red = blend_color[0]; state.blend.color.red = blend_color[0];
state.blend.color.green = blend_color[1]; state.blend.color.green = blend_color[1];
state.blend.color.blue = blend_color[2]; state.blend.color.blue = blend_color[2];

View File

@@ -573,7 +573,6 @@ bool Surface::Swap(const VideoCore::Material* mat) {
GetScaledWidth(), GetScaledHeight(), VideoCore::PixelFormatAsString(pixel_format), GetScaledWidth(), GetScaledHeight(), VideoCore::PixelFormatAsString(pixel_format),
addr, width, height, VideoCore::CustomPixelFormatAsString(format)); addr, width, height, VideoCore::CustomPixelFormatAsString(format));
is_custom = true;
custom_format = format; custom_format = format;
material = mat; material = mat;
@@ -615,13 +614,13 @@ HostTextureTag Surface::MakeTag() const noexcept {
.res_scale = alloc.res_scale, .res_scale = alloc.res_scale,
.tuple = alloc.tuple, .tuple = alloc.tuple,
.type = texture_type, .type = texture_type,
.is_custom = is_custom, .is_custom = True(flags & VideoCore::SurfaceFlagBits::Custom),
.has_normal = HasNormalMap(), .has_normal = HasNormalMap(),
}; };
} }
Framebuffer::Framebuffer(TextureRuntime& runtime, Surface* const color, u32 color_level, Framebuffer::Framebuffer(TextureRuntime& runtime, const Surface* color, u32 color_level,
Surface* const depth_stencil, u32 depth_level, const Pica::Regs& regs, const Surface* depth_stencil, u32 depth_level, const Pica::Regs& regs,
Common::Rectangle<u32> surfaces_rect) Common::Rectangle<u32> surfaces_rect)
: VideoCore::FramebufferBase{regs, color, color_level, : VideoCore::FramebufferBase{regs, color, color_level,
depth_stencil, depth_level, surfaces_rect} { depth_stencil, depth_level, surfaces_rect} {

View File

@@ -201,8 +201,8 @@ private:
class Framebuffer : public VideoCore::FramebufferBase { class Framebuffer : public VideoCore::FramebufferBase {
public: public:
explicit Framebuffer(TextureRuntime& runtime, Surface* const color, u32 color_level, explicit Framebuffer(TextureRuntime& runtime, const Surface* color, u32 color_level,
Surface* const depth_stencil, u32 depth_level, const Pica::Regs& regs, const Surface* depth_stencil, u32 depth_level, const Pica::Regs& regs,
Common::Rectangle<u32> surfaces_rect); Common::Rectangle<u32> surfaces_rect);
~Framebuffer(); ~Framebuffer();
@@ -243,7 +243,7 @@ private:
}; };
struct Traits { struct Traits {
using TextureRuntime = OpenGL::TextureRuntime; using Runtime = OpenGL::TextureRuntime;
using Sampler = OpenGL::Sampler; using Sampler = OpenGL::Sampler;
using Surface = OpenGL::Surface; using Surface = OpenGL::Surface;
using Framebuffer = OpenGL::Framebuffer; using Framebuffer = OpenGL::Framebuffer;