summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp15
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h16
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp30
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp52
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h50
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp85
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h18
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h2
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_stream_buffer.cpp2
13 files changed, 174 insertions, 114 deletions
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
index 0b5d18bcb..578aca789 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp
@@ -12,10 +12,10 @@
namespace OpenGL {
-OGLBufferCache::OGLBufferCache(size_t size) : stream_buffer(GL_ARRAY_BUFFER, size) {}
+OGLBufferCache::OGLBufferCache(std::size_t size) : stream_buffer(GL_ARRAY_BUFFER, size) {}
-GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, size_t size, size_t alignment,
- bool cache) {
+GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size,
+ std::size_t alignment, bool cache) {
auto& memory_manager = Core::System::GetInstance().GPU().MemoryManager();
const boost::optional<VAddr> cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr)};
@@ -53,7 +53,8 @@ GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, size_t size, siz
return uploaded_offset;
}
-GLintptr OGLBufferCache::UploadHostMemory(const void* raw_pointer, size_t size, size_t alignment) {
+GLintptr OGLBufferCache::UploadHostMemory(const void* raw_pointer, std::size_t size,
+ std::size_t alignment) {
AlignBuffer(alignment);
std::memcpy(buffer_ptr, raw_pointer, size);
GLintptr uploaded_offset = buffer_offset;
@@ -63,7 +64,7 @@ GLintptr OGLBufferCache::UploadHostMemory(const void* raw_pointer, size_t size,
return uploaded_offset;
}
-void OGLBufferCache::Map(size_t max_size) {
+void OGLBufferCache::Map(std::size_t max_size) {
bool invalidate;
std::tie(buffer_ptr, buffer_offset_base, invalidate) =
stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4);
@@ -81,10 +82,10 @@ GLuint OGLBufferCache::GetHandle() const {
return stream_buffer.GetHandle();
}
-void OGLBufferCache::AlignBuffer(size_t alignment) {
+void OGLBufferCache::AlignBuffer(std::size_t alignment) {
// Align the offset, not the mapped pointer
GLintptr offset_aligned =
- static_cast<GLintptr>(Common::AlignUp(static_cast<size_t>(buffer_offset), alignment));
+ static_cast<GLintptr>(Common::AlignUp(static_cast<std::size_t>(buffer_offset), alignment));
buffer_ptr += offset_aligned - buffer_offset;
buffer_offset = offset_aligned;
}
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h
index 6da862902..6c18461f4 100644
--- a/src/video_core/renderer_opengl/gl_buffer_cache.h
+++ b/src/video_core/renderer_opengl/gl_buffer_cache.h
@@ -19,32 +19,32 @@ struct CachedBufferEntry final {
return addr;
}
- size_t GetSizeInBytes() const {
+ std::size_t GetSizeInBytes() const {
return size;
}
VAddr addr;
- size_t size;
+ std::size_t size;
GLintptr offset;
- size_t alignment;
+ std::size_t alignment;
};
class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
public:
- explicit OGLBufferCache(size_t size);
+ explicit OGLBufferCache(std::size_t size);
- GLintptr UploadMemory(Tegra::GPUVAddr gpu_addr, size_t size, size_t alignment = 4,
+ GLintptr UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size, std::size_t alignment = 4,
bool cache = true);
- GLintptr UploadHostMemory(const void* raw_pointer, size_t size, size_t alignment = 4);
+ GLintptr UploadHostMemory(const void* raw_pointer, std::size_t size, std::size_t alignment = 4);
- void Map(size_t max_size);
+ void Map(std::size_t max_size);
void Unmap();
GLuint GetHandle() const;
protected:
- void AlignBuffer(size_t alignment);
+ void AlignBuffer(std::size_t alignment);
private:
OGLStreamBuffer stream_buffer;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 7e1bba67d..274c2dbcf 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -46,7 +46,7 @@ MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100,
RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info)
: emu_window{window}, screen_info{info}, buffer_cache(STREAM_BUFFER_SIZE) {
// Create sampler objects
- for (size_t i = 0; i < texture_samplers.size(); ++i) {
+ for (std::size_t i = 0; i < texture_samplers.size(); ++i) {
texture_samplers[i].Create();
state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
}
@@ -181,7 +181,7 @@ void RasterizerOpenGL::SetupShaders() {
u32 current_constbuffer_bindpoint = Tegra::Engines::Maxwell3D::Regs::MaxShaderStage;
u32 current_texture_bindpoint = 0;
- for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
+ for (std::size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
const auto& shader_config = gpu.regs.shader_config[index];
const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)};
@@ -190,12 +190,12 @@ void RasterizerOpenGL::SetupShaders() {
continue;
}
- const size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5
+ const std::size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5
GLShader::MaxwellUniformData ubo{};
ubo.SetFromRegs(gpu.state.shader_stages[stage]);
const GLintptr offset = buffer_cache.UploadHostMemory(
- &ubo, sizeof(ubo), static_cast<size_t>(uniform_buffer_alignment));
+ &ubo, sizeof(ubo), static_cast<std::size_t>(uniform_buffer_alignment));
// Bind the buffer
glBindBufferRange(GL_UNIFORM_BUFFER, stage, buffer_cache.GetHandle(), offset, sizeof(ubo));
@@ -238,10 +238,10 @@ void RasterizerOpenGL::SetupShaders() {
shader_program_manager->UseTrivialGeometryShader();
}
-size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
+std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
- size_t size = 0;
+ std::size_t size = 0;
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
if (!regs.vertex_array[index].IsEnabled())
continue;
@@ -299,7 +299,7 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb,
bool preserve_contents,
- boost::optional<size_t> single_color_target) {
+ boost::optional<std::size_t> single_color_target) {
MICROPROFILE_SCOPE(OpenGL_Framebuffer);
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
@@ -330,7 +330,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
} else {
// Multiple color attachments are enabled
std::array<GLenum, Maxwell::NumRenderTargets> buffers;
- for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
+ for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
Surface color_surface = res_cache.GetColorBufferSurface(index, preserve_contents);
buffers[index] = GL_COLOR_ATTACHMENT0 + regs.rt_control.GetMap(index);
glFramebufferTexture2D(
@@ -342,7 +342,7 @@ void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_dep
}
} else {
// No color attachments are enabled - zero out all of them
- for (size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
+ for (std::size_t index = 0; index < Maxwell::NumRenderTargets; ++index) {
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0 + static_cast<GLenum>(index), GL_TEXTURE_2D,
0, 0);
@@ -462,15 +462,15 @@ void RasterizerOpenGL::DrawArrays() {
state.draw.vertex_buffer = buffer_cache.GetHandle();
state.Apply();
- size_t buffer_size = CalculateVertexArraysSize();
+ std::size_t buffer_size = CalculateVertexArraysSize();
if (is_indexed) {
- buffer_size = Common::AlignUp<size_t>(buffer_size, 4) + index_buffer_size;
+ buffer_size = Common::AlignUp<std::size_t>(buffer_size, 4) + index_buffer_size;
}
// Uniform space for the 5 shader stages
buffer_size =
- Common::AlignUp<size_t>(buffer_size, 4) +
+ Common::AlignUp<std::size_t>(buffer_size, 4) +
(sizeof(GLShader::MaxwellUniformData) + uniform_buffer_alignment) * Maxwell::MaxShaderStage;
// Add space for at least 18 constant buffers
@@ -644,7 +644,7 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
MICROPROFILE_SCOPE(OpenGL_UBO);
const auto& gpu = Core::System::GetInstance().GPU();
const auto& maxwell3d = gpu.Maxwell3D();
- const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<size_t>(stage)];
+ const auto& shader_stage = maxwell3d.state.shader_stages[static_cast<std::size_t>(stage)];
const auto& entries = shader->GetShaderEntries().const_buffer_entries;
constexpr u64 max_binds = Tegra::Engines::Maxwell3D::Regs::MaxConstBuffers;
@@ -667,7 +667,7 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
continue;
}
- size_t size = 0;
+ std::size_t size = 0;
if (used_buffer.IsIndirect()) {
// Buffer is accessed indirectly, so upload the entire thing
@@ -689,7 +689,7 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shad
ASSERT_MSG(size <= MaxConstbufferSize, "Constbuffer too big");
GLintptr const_buffer_offset = buffer_cache.UploadMemory(
- buffer.address, size, static_cast<size_t>(uniform_buffer_alignment));
+ buffer.address, size, static_cast<std::size_t>(uniform_buffer_alignment));
// Now configure the bindpoint of the buffer inside the shader
glUniformBlockBinding(shader->GetProgramHandle(),
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 163412882..bf9560bdc 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -73,7 +73,7 @@ public:
};
/// Maximum supported size that a constbuffer can have in bytes.
- static constexpr size_t MaxConstbufferSize = 0x10000;
+ static constexpr std::size_t MaxConstbufferSize = 0x10000;
static_assert(MaxConstbufferSize % sizeof(GLvec4) == 0,
"The maximum size of a constbuffer must be a multiple of the size of GLvec4");
@@ -106,7 +106,7 @@ private:
*/
void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true,
bool preserve_contents = true,
- boost::optional<size_t> single_color_target = {});
+ boost::optional<std::size_t> single_color_target = {});
/*
* Configures the current constbuffers to use for the draw command.
@@ -180,12 +180,12 @@ private:
std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers;
- static constexpr size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
+ static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
OGLBufferCache buffer_cache;
OGLFramebuffer framebuffer;
GLint uniform_buffer_alignment;
- size_t CalculateVertexArraysSize() const;
+ std::size_t CalculateVertexArraysSize() const;
void SetupVertexArrays();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 32001e44b..86682d7cb 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -75,7 +75,7 @@ static VAddr TryGetCpuAddr(Tegra::GPUVAddr gpu_addr) {
return params;
}
-/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer(size_t index) {
+/*static*/ SurfaceParams SurfaceParams::CreateForFramebuffer(std::size_t index) {
const auto& config{Core::System::GetInstance().GPU().Maxwell3D().regs.rt[index]};
SurfaceParams params{};
params.addr = TryGetCpuAddr(config.Address());
@@ -167,6 +167,7 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form
{GL_RG8, GL_RG, GL_BYTE, ComponentType::SNorm, false}, // RG8S
{GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // RG32UI
{GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, ComponentType::UInt, false}, // R32UI
+ {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8
// Depth formats
{GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
@@ -203,7 +204,7 @@ static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) {
}
static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
- ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
+ ASSERT(static_cast<std::size_t>(pixel_format) < tex_format_tuples.size());
auto& format = tex_format_tuples[static_cast<unsigned int>(pixel_format)];
ASSERT(component_type == format.component_type);
@@ -213,6 +214,7 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType
static bool IsPixelFormatASTC(PixelFormat format) {
switch (format) {
case PixelFormat::ASTC_2D_4X4:
+ case PixelFormat::ASTC_2D_8X8:
return true;
default:
return false;
@@ -223,6 +225,8 @@ static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
switch (format) {
case PixelFormat::ASTC_2D_4X4:
return {4, 4};
+ case PixelFormat::ASTC_2D_8X8:
+ return {8, 8};
default:
LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
UNREACHABLE();
@@ -256,7 +260,7 @@ static bool IsFormatBCn(PixelFormat format) {
}
template <bool morton_to_gl, PixelFormat format>
-void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t gl_buffer_size,
+void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, std::size_t gl_buffer_size,
VAddr addr) {
constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT;
constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format);
@@ -267,7 +271,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t
const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
const std::vector<u8> data = Tegra::Texture::UnswizzleTexture(
addr, tile_size, bytes_per_pixel, stride, height, block_height);
- const size_t size_to_copy{std::min(gl_buffer_size, data.size())};
+ const std::size_t size_to_copy{std::min(gl_buffer_size, data.size())};
memcpy(gl_buffer, data.data(), size_to_copy);
} else {
// TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should
@@ -278,7 +282,7 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, size_t
}
}
-static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
+static constexpr std::array<void (*)(u32, u32, u32, u8*, std::size_t, VAddr),
SurfaceParams::MaxPixelFormat>
morton_to_gl_fns = {
// clang-format off
@@ -327,6 +331,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
MortonCopy<true, PixelFormat::RG8S>,
MortonCopy<true, PixelFormat::RG32UI>,
MortonCopy<true, PixelFormat::R32UI>,
+ MortonCopy<true, PixelFormat::ASTC_2D_8X8>,
MortonCopy<true, PixelFormat::Z32F>,
MortonCopy<true, PixelFormat::Z16>,
MortonCopy<true, PixelFormat::Z24S8>,
@@ -335,7 +340,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
// clang-format on
};
-static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
+static constexpr std::array<void (*)(u32, u32, u32, u8*, std::size_t, VAddr),
SurfaceParams::MaxPixelFormat>
gl_to_morton_fns = {
// clang-format off
@@ -386,6 +391,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, size_t, VAddr),
MortonCopy<false, PixelFormat::RG8S>,
MortonCopy<false, PixelFormat::RG32UI>,
MortonCopy<false, PixelFormat::R32UI>,
+ nullptr,
MortonCopy<false, PixelFormat::Z32F>,
MortonCopy<false, PixelFormat::Z16>,
MortonCopy<false, PixelFormat::Z24S8>,
@@ -513,9 +519,9 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
S8Z24 input_pixel{};
Z24S8 output_pixel{};
constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::S8Z24)};
- for (size_t y = 0; y < height; ++y) {
- for (size_t x = 0; x < width; ++x) {
- const size_t offset{bpp * (y * width + x)};
+ for (std::size_t y = 0; y < height; ++y) {
+ for (std::size_t x = 0; x < width; ++x) {
+ const std::size_t offset{bpp * (y * width + x)};
std::memcpy(&input_pixel, &data[offset], sizeof(S8Z24));
output_pixel.s8.Assign(input_pixel.s8);
output_pixel.z24.Assign(input_pixel.z24);
@@ -526,9 +532,9 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height) {
static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
constexpr auto bpp{CachedSurface::GetGLBytesPerPixel(PixelFormat::G8R8U)};
- for (size_t y = 0; y < height; ++y) {
- for (size_t x = 0; x < width; ++x) {
- const size_t offset{bpp * (y * width + x)};
+ for (std::size_t y = 0; y < height; ++y) {
+ for (std::size_t x = 0; x < width; ++x) {
+ const std::size_t offset{bpp * (y * width + x)};
const u8 temp{data[offset]};
data[offset] = data[offset + 1];
data[offset + 1] = temp;
@@ -544,7 +550,8 @@ static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format,
u32 width, u32 height) {
switch (pixel_format) {
- case PixelFormat::ASTC_2D_4X4: {
+ case PixelFormat::ASTC_2D_4X4:
+ case PixelFormat::ASTC_2D_8X8: {
// Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC.
u32 block_width{};
u32 block_height{};
@@ -591,13 +598,13 @@ void CachedSurface::LoadGLBuffer() {
UNREACHABLE();
}
- gl_buffer.resize(static_cast<size_t>(params.depth) * copy_size);
- morton_to_gl_fns[static_cast<size_t>(params.pixel_format)](
+ gl_buffer.resize(static_cast<std::size_t>(params.depth) * copy_size);
+ morton_to_gl_fns[static_cast<std::size_t>(params.pixel_format)](
params.width, params.block_height, params.height, gl_buffer.data(), copy_size,
params.addr);
} else {
const u8* const texture_src_data_end{texture_src_data +
- (static_cast<size_t>(params.depth) * copy_size)};
+ (static_cast<std::size_t>(params.depth) * copy_size)};
gl_buffer.assign(texture_src_data, texture_src_data_end);
}
@@ -616,7 +623,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
MICROPROFILE_SCOPE(OpenGL_TextureUL);
- ASSERT(gl_buffer.size() == static_cast<size_t>(params.width) * params.height *
+ ASSERT(gl_buffer.size() == static_cast<std::size_t>(params.width) * params.height *
GetGLBytesPerPixel(params.pixel_format) * params.depth);
const auto& rect{params.GetRect()};
@@ -624,8 +631,9 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
// Load data from memory to the surface
const GLint x0 = static_cast<GLint>(rect.left);
const GLint y0 = static_cast<GLint>(rect.bottom);
- const size_t buffer_offset =
- static_cast<size_t>(static_cast<size_t>(y0) * params.width + static_cast<size_t>(x0)) *
+ const std::size_t buffer_offset =
+ static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.width +
+ static_cast<std::size_t>(x0)) *
GetGLBytesPerPixel(params.pixel_format);
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
@@ -727,7 +735,7 @@ Surface RasterizerCacheOpenGL::GetDepthBufferSurface(bool preserve_contents) {
return GetSurface(depth_params, preserve_contents);
}
-Surface RasterizerCacheOpenGL::GetColorBufferSurface(size_t index, bool preserve_contents) {
+Surface RasterizerCacheOpenGL::GetColorBufferSurface(std::size_t index, bool preserve_contents) {
const auto& regs{Core::System::GetInstance().GPU().Maxwell3D().regs};
ASSERT(index < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets);
@@ -825,7 +833,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
auto source_format = GetFormatTuple(params.pixel_format, params.component_type);
auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type);
- size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes());
+ std::size_t buffer_size = std::max(params.SizeInBytes(), new_params.SizeInBytes());
glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo.handle);
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
@@ -849,7 +857,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during "
"reinterpretation but the texture is tiled.");
}
- size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
+ std::size_t remaining_size = new_params.SizeInBytes() - params.SizeInBytes();
std::vector<u8> data(remaining_size);
Memory::ReadBlock(new_params.addr + params.SizeInBytes(), data.data(), data.size());
glBufferSubData(GL_PIXEL_PACK_BUFFER, params.SizeInBytes(), remaining_size,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 57ea8593b..d7a4bc37f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -70,19 +70,20 @@ struct SurfaceParams {
RG8S = 42,
RG32UI = 43,
R32UI = 44,
+ ASTC_2D_8X8 = 45,
MaxColorFormat,
// Depth formats
- Z32F = 45,
- Z16 = 46,
+ Z32F = 46,
+ Z16 = 47,
MaxDepthFormat,
// DepthStencil formats
- Z24S8 = 47,
- S8Z24 = 48,
- Z32FS8 = 49,
+ Z24S8 = 48,
+ S8Z24 = 49,
+ Z32FS8 = 50,
MaxDepthStencilFormat,
@@ -90,7 +91,7 @@ struct SurfaceParams {
Invalid = 255,
};
- static constexpr size_t MaxPixelFormat = static_cast<size_t>(PixelFormat::Max);
+ static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
enum class ComponentType {
Invalid = 0,
@@ -192,6 +193,7 @@ struct SurfaceParams {
1, // RG8S
1, // RG32UI
1, // R32UI
+ 4, // ASTC_2D_8X8
1, // Z32F
1, // Z16
1, // Z24S8
@@ -199,8 +201,8 @@ struct SurfaceParams {
1, // Z32FS8
}};
- ASSERT(static_cast<size_t>(format) < compression_factor_table.size());
- return compression_factor_table[static_cast<size_t>(format)];
+ ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
+ return compression_factor_table[static_cast<std::size_t>(format)];
}
static constexpr u32 GetFormatBpp(PixelFormat format) {
@@ -253,6 +255,7 @@ struct SurfaceParams {
16, // RG8S
64, // RG32UI
32, // R32UI
+ 16, // ASTC_2D_8X8
32, // Z32F
16, // Z16
32, // Z24S8
@@ -260,8 +263,8 @@ struct SurfaceParams {
64, // Z32FS8
}};
- ASSERT(static_cast<size_t>(format) < bpp_table.size());
- return bpp_table[static_cast<size_t>(format)];
+ ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
+ return bpp_table[static_cast<std::size_t>(format)];
}
u32 GetFormatBpp() const {
@@ -316,6 +319,8 @@ struct SurfaceParams {
return PixelFormat::R11FG11FB10F;
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
return PixelFormat::B5G6R5U;
+ case Tegra::RenderTargetFormat::BGR5A1_UNORM:
+ return PixelFormat::A1B5G5R5U;
case Tegra::RenderTargetFormat::RGBA32_UINT:
return PixelFormat::RGBA32UI;
case Tegra::RenderTargetFormat::R8_UNORM:
@@ -522,6 +527,8 @@ struct SurfaceParams {
return PixelFormat::BC6H_SF16;
case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
return PixelFormat::ASTC_2D_4X4;
+ case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
+ return PixelFormat::ASTC_2D_8X8;
case Tegra::Texture::TextureFormat::R16_G16:
switch (component_type) {
case Tegra::Texture::ComponentType::FLOAT:
@@ -576,6 +583,7 @@ struct SurfaceParams {
case Tegra::RenderTargetFormat::RG16_UNORM:
case Tegra::RenderTargetFormat::R16_UNORM:
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
+ case Tegra::RenderTargetFormat::BGR5A1_UNORM:
case Tegra::RenderTargetFormat::RG8_UNORM:
case Tegra::RenderTargetFormat::RGBA16_UNORM:
return ComponentType::UNorm;
@@ -636,16 +644,18 @@ struct SurfaceParams {
}
static SurfaceType GetFormatType(PixelFormat pixel_format) {
- if (static_cast<size_t>(pixel_format) < static_cast<size_t>(PixelFormat::MaxColorFormat)) {
+ if (static_cast<std::size_t>(pixel_format) <
+ static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
return SurfaceType::ColorTexture;
}
- if (static_cast<size_t>(pixel_format) < static_cast<size_t>(PixelFormat::MaxDepthFormat)) {
+ if (static_cast<std::size_t>(pixel_format) <
+ static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
return SurfaceType::Depth;
}
- if (static_cast<size_t>(pixel_format) <
- static_cast<size_t>(PixelFormat::MaxDepthStencilFormat)) {
+ if (static_cast<std::size_t>(pixel_format) <
+ static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
return SurfaceType::DepthStencil;
}
@@ -659,7 +669,7 @@ struct SurfaceParams {
MathUtil::Rectangle<u32> GetRect() const;
/// Returns the size of this surface in bytes, adjusted for compression
- size_t SizeInBytes() const {
+ std::size_t SizeInBytes() const {
const u32 compression_factor{GetCompressionFactor(pixel_format)};
ASSERT(width % compression_factor == 0);
ASSERT(height % compression_factor == 0);
@@ -671,7 +681,7 @@ struct SurfaceParams {
static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config);
/// Creates SurfaceParams from a framebuffer configuration
- static SurfaceParams CreateForFramebuffer(size_t index);
+ static SurfaceParams CreateForFramebuffer(std::size_t index);
/// Creates SurfaceParams for a depth buffer configuration
static SurfaceParams CreateForDepthBuffer(u32 zeta_width, u32 zeta_height,
@@ -694,7 +704,7 @@ struct SurfaceParams {
u32 height;
u32 depth;
u32 unaligned_height;
- size_t size_in_bytes;
+ std::size_t size_in_bytes;
SurfaceTarget target;
};
@@ -711,7 +721,7 @@ struct SurfaceReserveKey : Common::HashableStruct<OpenGL::SurfaceParams> {
namespace std {
template <>
struct hash<SurfaceReserveKey> {
- size_t operator()(const SurfaceReserveKey& k) const {
+ std::size_t operator()(const SurfaceReserveKey& k) const {
return k.Hash();
}
};
@@ -727,7 +737,7 @@ public:
return params.addr;
}
- size_t GetSizeInBytes() const {
+ std::size_t GetSizeInBytes() const {
return params.size_in_bytes;
}
@@ -775,7 +785,7 @@ public:
Surface GetDepthBufferSurface(bool preserve_contents);
/// Get the color surface based on the framebuffer configuration and the specified render target
- Surface GetColorBufferSurface(size_t index, bool preserve_contents);
+ Surface GetColorBufferSurface(std::size_t index, bool preserve_contents);
/// Flushes the surface to Switch memory
void FlushSurface(const Surface& surface);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index 61080f5cc..894fe6eae 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -14,7 +14,7 @@ namespace OpenGL {
/// Gets the address for the specified shader stage program
static VAddr GetShaderAddress(Maxwell::ShaderProgram program) {
const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
- const auto& shader_config = gpu.regs.shader_config[static_cast<size_t>(program)];
+ const auto& shader_config = gpu.regs.shader_config[static_cast<std::size_t>(program)];
return *gpu.memory_manager.GpuToCpuAddress(gpu.regs.code_address.CodeAddress() +
shader_config.offset);
}
@@ -28,7 +28,7 @@ static GLShader::ProgramCode GetShaderCode(VAddr addr) {
/// Helper function to set shader uniform block bindings for a single shader stage
static void SetShaderUniformBlockBinding(GLuint shader, const char* name,
- Maxwell::ShaderStage binding, size_t expected_size) {
+ Maxwell::ShaderStage binding, std::size_t expected_size) {
const GLuint ub_index = glGetUniformBlockIndex(shader, name);
if (ub_index == GL_INVALID_INDEX) {
return;
@@ -36,7 +36,7 @@ static void SetShaderUniformBlockBinding(GLuint shader, const char* name,
GLint ub_size = 0;
glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size);
- ASSERT_MSG(static_cast<size_t>(ub_size) == expected_size,
+ ASSERT_MSG(static_cast<std::size_t>(ub_size) == expected_size,
"Uniform block size did not match! Got {}, expected {}", ub_size, expected_size);
glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding));
}
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h
index 6e6febcbc..9bafe43a9 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.h
+++ b/src/video_core/renderer_opengl/gl_shader_cache.h
@@ -28,7 +28,7 @@ public:
}
/// Gets the size of the shader in guest memory, required for cache management
- size_t GetSizeInBytes() const {
+ std::size_t GetSizeInBytes() const {
return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64);
}
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 2d56370c7..252ff18fc 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -189,7 +189,7 @@ public:
private:
void AppendIndentation() {
- shader_source.append(static_cast<size_t>(scope) * 4, ' ');
+ shader_source.append(static_cast<std::size_t>(scope) * 4, ' ');
}
std::string shader_source;
@@ -208,7 +208,7 @@ public:
UnsignedInteger,
};
- GLSLRegister(size_t index, const std::string& suffix) : index{index}, suffix{suffix} {}
+ GLSLRegister(std::size_t index, const std::string& suffix) : index{index}, suffix{suffix} {}
/// Gets the GLSL type string for a register
static std::string GetTypeString() {
@@ -226,12 +226,12 @@ public:
}
/// Returns the index of the register
- size_t GetIndex() const {
+ std::size_t GetIndex() const {
return index;
}
private:
- const size_t index;
+ const std::size_t index;
const std::string& suffix;
};
@@ -468,7 +468,7 @@ public:
/// necessary.
std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
bool is_array) {
- const size_t offset = static_cast<size_t>(sampler.index.Value());
+ const std::size_t offset = static_cast<std::size_t>(sampler.index.Value());
// If this sampler has already been used, return the existing mapping.
const auto itr =
@@ -481,7 +481,7 @@ public:
}
// Otherwise create a new mapping for this sampler
- const size_t next_index = used_samplers.size();
+ const std::size_t next_index = used_samplers.size();
const SamplerEntry entry{stage, offset, next_index, type, is_array};
used_samplers.emplace_back(entry);
return entry.GetName();
@@ -531,7 +531,7 @@ private:
void BuildRegisterList() {
regs.reserve(Register::NumRegisters);
- for (size_t index = 0; index < Register::NumRegisters; ++index) {
+ for (std::size_t index = 0; index < Register::NumRegisters; ++index) {
regs.emplace_back(index, suffix);
}
}
@@ -862,7 +862,7 @@ private:
*/
bool IsSchedInstruction(u32 offset) const {
// sched instructions appear once every 4 instructions.
- static constexpr size_t SchedPeriod = 4;
+ static constexpr std::size_t SchedPeriod = 4;
u32 absolute_offset = offset - main_offset;
return (absolute_offset % SchedPeriod) == 0;
@@ -930,7 +930,7 @@ private:
std::string result;
result += '(';
- for (size_t i = 0; i < shift_amounts.size(); ++i) {
+ for (std::size_t i = 0; i < shift_amounts.size(); ++i) {
if (i)
result += '|';
result += "(((" + imm_lut + " >> (((" + op_c + " >> " + shift_amounts[i] +
@@ -956,7 +956,7 @@ private:
ASSERT_MSG(instr.texs.nodep == 0, "TEXS nodep not implemented");
- size_t written_components = 0;
+ std::size_t written_components = 0;
for (u32 component = 0; component < 4; ++component) {
if (!instr.texs.IsComponentEnabled(component)) {
continue;
@@ -1510,8 +1510,6 @@ private:
case OpCode::Id::LEA_IMM:
case OpCode::Id::LEA_RZ:
case OpCode::Id::LEA_HI: {
- std::string op_a;
- std::string op_b;
std::string op_c;
switch (opcode->GetId()) {
@@ -1772,13 +1770,34 @@ private:
case OpCode::Type::Memory: {
switch (opcode->GetId()) {
case OpCode::Id::LD_A: {
- ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
// Note: Shouldn't this be interp mode flat? As in no interpolation made.
+ ASSERT_MSG(instr.gpr8.Value() == Register::ZeroIndex,
+ "Indirect attribute loads are not supported");
+ ASSERT_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) == 0,
+ "Unaligned attribute loads are not supported");
Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Perspective,
Tegra::Shader::IpaSampleMode::Default};
- regs.SetRegisterToInputAttibute(instr.gpr0, instr.attribute.fmt20.element,
- instr.attribute.fmt20.index, input_mode);
+
+ u32 next_element = instr.attribute.fmt20.element;
+ u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value());
+
+ const auto LoadNextElement = [&](u32 reg_offset) {
+ regs.SetRegisterToInputAttibute(instr.gpr0.Value() + reg_offset, next_element,
+ static_cast<Attribute::Index>(next_index),
+ input_mode);
+
+ // Load the next attribute element into the following register. If the element
+ // to load goes beyond the vec4 size, load the first element of the next
+ // attribute.
+ next_element = (next_element + 1) % 4;
+ next_index = next_index + (next_element == 0 ? 1 : 0);
+ };
+
+ const u32 num_words = static_cast<u32>(instr.attribute.fmt20.size.Value()) + 1;
+ for (u32 reg_offset = 0; reg_offset < num_words; ++reg_offset) {
+ LoadNextElement(reg_offset);
+ }
break;
}
case OpCode::Id::LD_C: {
@@ -1820,9 +1839,31 @@ private:
break;
}
case OpCode::Id::ST_A: {
- ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested");
- regs.SetOutputAttributeToRegister(instr.attribute.fmt20.index,
- instr.attribute.fmt20.element, instr.gpr0);
+ ASSERT_MSG(instr.gpr8.Value() == Register::ZeroIndex,
+ "Indirect attribute loads are not supported");
+ ASSERT_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) == 0,
+ "Unaligned attribute loads are not supported");
+
+ u32 next_element = instr.attribute.fmt20.element;
+ u32 next_index = static_cast<u32>(instr.attribute.fmt20.index.Value());
+
+ const auto StoreNextElement = [&](u32 reg_offset) {
+ regs.SetOutputAttributeToRegister(static_cast<Attribute::Index>(next_index),
+ next_element,
+ instr.gpr0.Value() + reg_offset);
+
+ // Load the next attribute element into the following register. If the element
+ // to load goes beyond the vec4 size, load the first element of the next
+ // attribute.
+ next_element = (next_element + 1) % 4;
+ next_index = next_index + (next_element == 0 ? 1 : 0);
+ };
+
+ const u32 num_words = static_cast<u32>(instr.attribute.fmt20.size.Value()) + 1;
+ for (u32 reg_offset = 0; reg_offset < num_words; ++reg_offset) {
+ StoreNextElement(reg_offset);
+ }
+
break;
}
case OpCode::Id::TEX: {
@@ -1894,8 +1935,8 @@ private:
UNREACHABLE();
}
}
- size_t dest_elem{};
- for (size_t elem = 0; elem < 4; ++elem) {
+ std::size_t dest_elem{};
+ for (std::size_t elem = 0; elem < 4; ++elem) {
if (!instr.tex.IsComponentEnabled(elem)) {
// Skip disabled components
continue;
@@ -1999,8 +2040,8 @@ private:
const std::string texture = "textureGather(" + sampler + ", coords, " +
std::to_string(instr.tld4.component) + ')';
- size_t dest_elem{};
- for (size_t elem = 0; elem < 4; ++elem) {
+ std::size_t dest_elem{};
+ for (std::size_t elem = 0; elem < 4; ++elem) {
if (!instr.tex.IsComponentEnabled(elem)) {
// Skip disabled components
continue;
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index a43e2997b..d53b93ad5 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -13,7 +13,7 @@
namespace OpenGL::GLShader {
-constexpr size_t MAX_PROGRAM_CODE_LENGTH{0x1000};
+constexpr std::size_t MAX_PROGRAM_CODE_LENGTH{0x1000};
using ProgramCode = std::vector<u64>;
class ConstBufferEntry {
@@ -51,7 +51,7 @@ public:
}
std::string GetName() const {
- return BufferBaseNames[static_cast<size_t>(stage)] + std::to_string(index);
+ return BufferBaseNames[static_cast<std::size_t>(stage)] + std::to_string(index);
}
u32 GetHash() const {
@@ -74,15 +74,15 @@ class SamplerEntry {
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
public:
- SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index,
+ SamplerEntry(Maxwell::ShaderStage stage, std::size_t offset, std::size_t index,
Tegra::Shader::TextureType type, bool is_array)
: offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {}
- size_t GetOffset() const {
+ std::size_t GetOffset() const {
return offset;
}
- size_t GetIndex() const {
+ std::size_t GetIndex() const {
return sampler_index;
}
@@ -91,7 +91,7 @@ public:
}
std::string GetName() const {
- return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '_' +
+ return std::string(TextureSamplerNames[static_cast<std::size_t>(stage)]) + '_' +
std::to_string(sampler_index);
}
@@ -133,7 +133,7 @@ public:
}
static std::string GetArrayName(Maxwell::ShaderStage stage) {
- return TextureSamplerNames[static_cast<size_t>(stage)];
+ return TextureSamplerNames[static_cast<std::size_t>(stage)];
}
private:
@@ -143,9 +143,9 @@ private:
/// Offset in TSC memory from which to read the sampler object, as specified by the sampling
/// instruction.
- size_t offset;
+ std::size_t offset;
Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used.
- size_t sampler_index; ///< Value used to index into the generated GLSL sampler array.
+ std::size_t sampler_index; ///< Value used to index into the generated GLSL sampler array.
Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc)
bool is_array; ///< Whether the texture is being sampled as an array texture or not.
};
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index 533e42caa..b86cd96e8 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -12,7 +12,7 @@
namespace OpenGL::GLShader {
/// Number of OpenGL texture samplers that can be used in the fragment shader
-static constexpr size_t NumTextureSamplers = 32;
+static constexpr std::size_t NumTextureSamplers = 32;
using Tegra::Engines::Maxwell3D;
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 6f70deb96..af99132ba 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -272,7 +272,7 @@ void OpenGLState::Apply() const {
}
// Clip distance
- for (size_t i = 0; i < clip_distance.size(); ++i) {
+ for (std::size_t i = 0; i < clip_distance.size(); ++i) {
if (clip_distance[i] != cur_state.clip_distance[i]) {
if (clip_distance[i]) {
glEnable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i));
diff --git a/src/video_core/renderer_opengl/gl_stream_buffer.cpp b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
index aadf68f16..664f3ca20 100644
--- a/src/video_core/renderer_opengl/gl_stream_buffer.cpp
+++ b/src/video_core/renderer_opengl/gl_stream_buffer.cpp
@@ -61,7 +61,7 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
mapped_size = size;
if (alignment > 0) {
- buffer_pos = Common::AlignUp<size_t>(buffer_pos, alignment);
+ buffer_pos = Common::AlignUp<std::size_t>(buffer_pos, alignment);
}
bool invalidate = false;