summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/core/hle/service/am/am.cpp7
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp92
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h25
-rw-r--r--src/core/hle/service/vi/vi.cpp62
-rw-r--r--src/video_core/engines/shader_bytecode.h10
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp242
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h7
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp4
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h2
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp32
-rw-r--r--src/video_core/renderer_opengl/gl_state.h12
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp63
-rw-r--r--src/video_core/shader/decode/memory.cpp70
-rw-r--r--src/video_core/textures/texture.h2
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp20
-rw-r--r--src/yuzu/configuration/configure_graphics.h2
-rw-r--r--src/yuzu/loading_screen.ui5
-rw-r--r--src/yuzu/main.cpp16
19 files changed, 378 insertions, 302 deletions
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index d1cbe0e44..3f009d2b7 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -322,14 +322,15 @@ void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& c
void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
+
// TODO(Subv): Find out how AM determines the display to use, for now just
// create the layer in the Default display.
- u64 display_id = nvflinger->OpenDisplay("Default");
- u64 layer_id = nvflinger->CreateLayer(display_id);
+ const auto display_id = nvflinger->OpenDisplay("Default");
+ const auto layer_id = nvflinger->CreateLayer(*display_id);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push(layer_id);
+ rb.Push(*layer_id);
}
void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) {
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 8dfc0df03..cde06916d 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -46,7 +46,7 @@ void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) {
nvdrv = std::move(instance);
}
-u64 NVFlinger::OpenDisplay(std::string_view name) {
+std::optional<u64> NVFlinger::OpenDisplay(std::string_view name) {
LOG_DEBUG(Service, "Opening \"{}\" display", name);
// TODO(Subv): Currently we only support the Default display.
@@ -54,32 +54,48 @@ u64 NVFlinger::OpenDisplay(std::string_view name) {
const auto itr = std::find_if(displays.begin(), displays.end(),
[&](const Display& display) { return display.name == name; });
-
- ASSERT(itr != displays.end());
+ if (itr == displays.end()) {
+ return {};
+ }
return itr->id;
}
-u64 NVFlinger::CreateLayer(u64 display_id) {
- auto& display = FindDisplay(display_id);
+std::optional<u64> NVFlinger::CreateLayer(u64 display_id) {
+ auto* const display = FindDisplay(display_id);
+
+ if (display == nullptr) {
+ return {};
+ }
- ASSERT_MSG(display.layers.empty(), "Only one layer is supported per display at the moment");
+ ASSERT_MSG(display->layers.empty(), "Only one layer is supported per display at the moment");
const u64 layer_id = next_layer_id++;
const u32 buffer_queue_id = next_buffer_queue_id++;
auto buffer_queue = std::make_shared<BufferQueue>(buffer_queue_id, layer_id);
- display.layers.emplace_back(layer_id, buffer_queue);
+ display->layers.emplace_back(layer_id, buffer_queue);
buffer_queues.emplace_back(std::move(buffer_queue));
return layer_id;
}
-u32 NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const {
- const auto& layer = FindLayer(display_id, layer_id);
- return layer.buffer_queue->GetId();
+std::optional<u32> NVFlinger::FindBufferQueueId(u64 display_id, u64 layer_id) const {
+ const auto* const layer = FindLayer(display_id, layer_id);
+
+ if (layer == nullptr) {
+ return {};
+ }
+
+ return layer->buffer_queue->GetId();
}
-Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::GetVsyncEvent(u64 display_id) {
- return FindDisplay(display_id).vsync_event.readable;
+Kernel::SharedPtr<Kernel::ReadableEvent> NVFlinger::FindVsyncEvent(u64 display_id) const {
+ auto* const display = FindDisplay(display_id);
+
+ if (display == nullptr) {
+ return nullptr;
+ }
+
+ return display->vsync_event.readable;
}
std::shared_ptr<BufferQueue> NVFlinger::FindBufferQueue(u32 id) const {
@@ -90,40 +106,60 @@ std::shared_ptr<BufferQueue> NVFlinger::FindBufferQueue(u32 id) const {
return *itr;
}
-Display& NVFlinger::FindDisplay(u64 display_id) {
+Display* NVFlinger::FindDisplay(u64 display_id) {
const auto itr = std::find_if(displays.begin(), displays.end(),
[&](const Display& display) { return display.id == display_id; });
- ASSERT(itr != displays.end());
- return *itr;
+ if (itr == displays.end()) {
+ return nullptr;
+ }
+
+ return &*itr;
}
-const Display& NVFlinger::FindDisplay(u64 display_id) const {
+const Display* NVFlinger::FindDisplay(u64 display_id) const {
const auto itr = std::find_if(displays.begin(), displays.end(),
[&](const Display& display) { return display.id == display_id; });
- ASSERT(itr != displays.end());
- return *itr;
+ if (itr == displays.end()) {
+ return nullptr;
+ }
+
+ return &*itr;
}
-Layer& NVFlinger::FindLayer(u64 display_id, u64 layer_id) {
- auto& display = FindDisplay(display_id);
+Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) {
+ auto* const display = FindDisplay(display_id);
- const auto itr = std::find_if(display.layers.begin(), display.layers.end(),
+ if (display == nullptr) {
+ return nullptr;
+ }
+
+ const auto itr = std::find_if(display->layers.begin(), display->layers.end(),
[&](const Layer& layer) { return layer.id == layer_id; });
- ASSERT(itr != display.layers.end());
- return *itr;
+ if (itr == display->layers.end()) {
+ return nullptr;
+ }
+
+ return &*itr;
}
-const Layer& NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
- const auto& display = FindDisplay(display_id);
+const Layer* NVFlinger::FindLayer(u64 display_id, u64 layer_id) const {
+ const auto* const display = FindDisplay(display_id);
+
+ if (display == nullptr) {
+ return nullptr;
+ }
- const auto itr = std::find_if(display.layers.begin(), display.layers.end(),
+ const auto itr = std::find_if(display->layers.begin(), display->layers.end(),
[&](const Layer& layer) { return layer.id == layer_id; });
- ASSERT(itr != display.layers.end());
- return *itr;
+ if (itr == display->layers.end()) {
+ return nullptr;
+ }
+
+ return &*itr;
}
void NVFlinger::Compose() {
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index 83e974ed3..4c55e99f4 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -6,6 +6,7 @@
#include <array>
#include <memory>
+#include <optional>
#include <string>
#include <string_view>
#include <vector>
@@ -58,16 +59,24 @@ public:
void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance);
/// Opens the specified display and returns the ID.
- u64 OpenDisplay(std::string_view name);
+ ///
+ /// If an invalid display name is provided, then an empty optional is returned.
+ std::optional<u64> OpenDisplay(std::string_view name);
/// Creates a layer on the specified display and returns the layer ID.
- u64 CreateLayer(u64 display_id);
+ ///
+ /// If an invalid display ID is specified, then an empty optional is returned.
+ std::optional<u64> CreateLayer(u64 display_id);
/// Finds the buffer queue ID of the specified layer in the specified display.
- u32 FindBufferQueueId(u64 display_id, u64 layer_id) const;
+ ///
+ /// If an invalid display ID or layer ID is provided, then an empty optional is returned.
+ std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id) const;
/// Gets the vsync event for the specified display.
- Kernel::SharedPtr<Kernel::ReadableEvent> GetVsyncEvent(u64 display_id);
+ ///
+ /// If an invalid display ID is provided, then nullptr is returned.
+ Kernel::SharedPtr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const;
/// Obtains a buffer queue identified by the ID.
std::shared_ptr<BufferQueue> FindBufferQueue(u32 id) const;
@@ -78,16 +87,16 @@ public:
private:
/// Finds the display identified by the specified ID.
- Display& FindDisplay(u64 display_id);
+ Display* FindDisplay(u64 display_id);
/// Finds the display identified by the specified ID.
- const Display& FindDisplay(u64 display_id) const;
+ const Display* FindDisplay(u64 display_id) const;
/// Finds the layer identified by the specified ID in the desired display.
- Layer& FindLayer(u64 display_id, u64 layer_id);
+ Layer* FindLayer(u64 display_id, u64 layer_id);
/// Finds the layer identified by the specified ID in the desired display.
- const Layer& FindLayer(u64 display_id, u64 layer_id) const;
+ const Layer* FindLayer(u64 display_id, u64 layer_id) const;
std::shared_ptr<Nvidia::Module> nvdrv;
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index fe08c38f2..a317a2885 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -34,6 +34,7 @@ namespace Service::VI {
constexpr ResultCode ERR_OPERATION_FAILED{ErrorModule::VI, 1};
constexpr ResultCode ERR_UNSUPPORTED{ErrorModule::VI, 6};
+constexpr ResultCode ERR_NOT_FOUND{ErrorModule::VI, 7};
struct DisplayInfo {
/// The name of this particular display.
@@ -838,11 +839,16 @@ private:
"(STUBBED) called. unknown=0x{:08X}, display=0x{:016X}, aruid=0x{:016X}",
unknown, display, aruid);
- const u64 layer_id = nv_flinger->CreateLayer(display);
+ const auto layer_id = nv_flinger->CreateLayer(display);
+ if (!layer_id) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NOT_FOUND);
+ return;
+ }
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push(layer_id);
+ rb.Push(*layer_id);
}
void AddToLayerStack(Kernel::HLERequestContext& ctx) {
@@ -950,9 +956,16 @@ private:
ASSERT_MSG(name == "Default", "Non-default displays aren't supported yet");
+ const auto display_id = nv_flinger->OpenDisplay(name);
+ if (!display_id) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NOT_FOUND);
+ return;
+ }
+
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
- rb.Push<u64>(nv_flinger->OpenDisplay(name));
+ rb.Push<u64>(*display_id);
}
void CloseDisplay(Kernel::HLERequestContext& ctx) {
@@ -1043,10 +1056,21 @@ private:
LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}, aruid=0x{:016X}", layer_id, aruid);
- const u64 display_id = nv_flinger->OpenDisplay(display_name);
- const u32 buffer_queue_id = nv_flinger->FindBufferQueueId(display_id, layer_id);
+ const auto display_id = nv_flinger->OpenDisplay(display_name);
+ if (!display_id) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NOT_FOUND);
+ return;
+ }
+
+ const auto buffer_queue_id = nv_flinger->FindBufferQueueId(*display_id, layer_id);
+ if (!buffer_queue_id) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NOT_FOUND);
+ return;
+ }
- NativeWindow native_window{buffer_queue_id};
+ NativeWindow native_window{*buffer_queue_id};
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
@@ -1062,13 +1086,24 @@ private:
// TODO(Subv): What's the difference between a Stray and a Managed layer?
- const u64 layer_id = nv_flinger->CreateLayer(display_id);
- const u32 buffer_queue_id = nv_flinger->FindBufferQueueId(display_id, layer_id);
+ const auto layer_id = nv_flinger->CreateLayer(display_id);
+ if (!layer_id) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NOT_FOUND);
+ return;
+ }
+
+ const auto buffer_queue_id = nv_flinger->FindBufferQueueId(display_id, *layer_id);
+ if (!buffer_queue_id) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NOT_FOUND);
+ return;
+ }
- NativeWindow native_window{buffer_queue_id};
+ NativeWindow native_window{*buffer_queue_id};
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(RESULT_SUCCESS);
- rb.Push(layer_id);
+ rb.Push(*layer_id);
rb.Push<u64>(ctx.WriteBuffer(native_window.Serialize()));
}
@@ -1088,7 +1123,12 @@ private:
LOG_WARNING(Service_VI, "(STUBBED) called. display_id=0x{:016X}", display_id);
- const auto vsync_event = nv_flinger->GetVsyncEvent(display_id);
+ const auto vsync_event = nv_flinger->FindVsyncEvent(display_id);
+ if (!vsync_event) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ERR_NOT_FOUND);
+ return;
+ }
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 713b01c9f..269df9437 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -217,9 +217,9 @@ enum class StoreType : u64 {
Signed8 = 1,
Unsigned16 = 2,
Signed16 = 3,
- Bytes32 = 4,
- Bytes64 = 5,
- Bytes128 = 6,
+ Bits32 = 4,
+ Bits64 = 5,
+ Bits128 = 6,
};
enum class IMinMaxExchange : u64 {
@@ -981,6 +981,10 @@ union Instruction {
}
return false;
}
+
+ bool IsComponentEnabled(std::size_t component) const {
+ return ((1ULL << component) & component_mask) != 0;
+ }
} txq;
union {
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 585709fe5..c806b7da7 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -1015,11 +1015,8 @@ void RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, const Shader& s
if (surface != nullptr) {
unit.texture =
entry.IsArray() ? surface->TextureLayer().handle : surface->Texture().handle;
- unit.target = entry.IsArray() ? surface->TargetLayer() : surface->Target();
- unit.swizzle.r = MaxwellToGL::SwizzleSource(texture.tic.x_source);
- unit.swizzle.g = MaxwellToGL::SwizzleSource(texture.tic.y_source);
- unit.swizzle.b = MaxwellToGL::SwizzleSource(texture.tic.z_source);
- unit.swizzle.a = MaxwellToGL::SwizzleSource(texture.tic.w_source);
+ surface->UpdateSwizzle(texture.tic.x_source, texture.tic.y_source, texture.tic.z_source,
+ texture.tic.w_source);
} else {
// Can occur when texture addr is null or its memory is unmapped/invalid
unit.texture = 0;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 50286432d..a79eee03e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -18,7 +18,6 @@
#include "video_core/morton.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
-#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/renderer_opengl/utils.h"
#include "video_core/surface.h"
#include "video_core/textures/astc.h"
@@ -44,14 +43,14 @@ struct FormatTuple {
bool compressed;
};
-static void ApplyTextureDefaults(GLenum target, u32 max_mip_level) {
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, max_mip_level - 1);
+static void ApplyTextureDefaults(GLuint texture, u32 max_mip_level) {
+ glTextureParameteri(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, max_mip_level - 1);
if (max_mip_level == 1) {
- glTexParameterf(target, GL_TEXTURE_LOD_BIAS, 1000.0);
+ glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0);
}
}
@@ -529,55 +528,41 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
CachedSurface::CachedSurface(const SurfaceParams& params)
: params(params), gl_target(SurfaceTargetToGL(params.target)),
cached_size_in_bytes(params.size_in_bytes) {
- texture.Create();
- const auto& rect{params.GetRect()};
-
- // Keep track of previous texture bindings
- OpenGLState cur_state = OpenGLState::GetCurState();
- const auto& old_tex = cur_state.texture_units[0];
- SCOPE_EXIT({
- cur_state.texture_units[0] = old_tex;
- cur_state.Apply();
- });
-
- cur_state.texture_units[0].texture = texture.handle;
- cur_state.texture_units[0].target = SurfaceTargetToGL(params.target);
- cur_state.Apply();
- glActiveTexture(GL_TEXTURE0);
+ texture.Create(gl_target);
+
+ // TODO(Rodrigo): Using params.GetRect() returns a different size than using its Mip*(0)
+ // alternatives. This signals a bug on those functions.
+ const auto width = static_cast<GLsizei>(params.MipWidth(0));
+ const auto height = static_cast<GLsizei>(params.MipHeight(0));
const auto& format_tuple = GetFormatTuple(params.pixel_format, params.component_type);
gl_internal_format = format_tuple.internal_format;
- gl_is_compressed = format_tuple.compressed;
- if (!format_tuple.compressed) {
- // Only pre-create the texture for non-compressed textures.
- switch (params.target) {
- case SurfaceTarget::Texture1D:
- glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level,
- format_tuple.internal_format, rect.GetWidth());
- break;
- case SurfaceTarget::Texture2D:
- case SurfaceTarget::TextureCubemap:
- glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level,
- format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());
- break;
- case SurfaceTarget::Texture3D:
- case SurfaceTarget::Texture2DArray:
- case SurfaceTarget::TextureCubeArray:
- glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
- format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
- params.depth);
- break;
- default:
- LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
- static_cast<u32>(params.target));
- UNREACHABLE();
- glTexStorage2D(GL_TEXTURE_2D, params.max_mip_level, format_tuple.internal_format,
- rect.GetWidth(), rect.GetHeight());
- }
+ switch (params.target) {
+ case SurfaceTarget::Texture1D:
+ glTextureStorage1D(texture.handle, params.max_mip_level, format_tuple.internal_format,
+ width);
+ break;
+ case SurfaceTarget::Texture2D:
+ case SurfaceTarget::TextureCubemap:
+ glTextureStorage2D(texture.handle, params.max_mip_level, format_tuple.internal_format,
+ width, height);
+ break;
+ case SurfaceTarget::Texture3D:
+ case SurfaceTarget::Texture2DArray:
+ case SurfaceTarget::TextureCubeArray:
+ glTextureStorage3D(texture.handle, params.max_mip_level, format_tuple.internal_format,
+ width, height, params.depth);
+ break;
+ default:
+ LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
+ static_cast<u32>(params.target));
+ UNREACHABLE();
+ glTextureStorage2D(texture.handle, params.max_mip_level, format_tuple.internal_format,
+ width, height);
}
- ApplyTextureDefaults(SurfaceTargetToGL(params.target), params.max_mip_level);
+ ApplyTextureDefaults(texture.handle, params.max_mip_level);
OpenGL::LabelGLObject(GL_TEXTURE, texture.handle, params.addr, params.IdentityString());
@@ -751,63 +736,50 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
const auto& rect{params.GetRect(mip_map)};
// Load data from memory to the surface
- const GLint x0 = static_cast<GLint>(rect.left);
- const GLint y0 = static_cast<GLint>(rect.bottom);
- std::size_t buffer_offset =
+ const auto x0 = static_cast<GLint>(rect.left);
+ const auto y0 = static_cast<GLint>(rect.bottom);
+ auto buffer_offset =
static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
static_cast<std::size_t>(x0)) *
GetBytesPerPixel(params.pixel_format);
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
- const GLuint target_tex = texture.handle;
- OpenGLState cur_state = OpenGLState::GetCurState();
-
- const auto& old_tex = cur_state.texture_units[0];
- SCOPE_EXIT({
- cur_state.texture_units[0] = old_tex;
- cur_state.Apply();
- });
- cur_state.texture_units[0].texture = target_tex;
- cur_state.texture_units[0].target = SurfaceTargetToGL(params.target);
- cur_state.Apply();
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
ASSERT(params.MipWidth(mip_map) * GetBytesPerPixel(params.pixel_format) % 4 == 0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
- GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
- glActiveTexture(GL_TEXTURE0);
+ const auto image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
if (tuple.compressed) {
switch (params.target) {
case SurfaceTarget::Texture2D:
- glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
- static_cast<GLsizei>(params.MipWidth(mip_map)),
- static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size,
- &gl_buffer[mip_map][buffer_offset]);
+ glCompressedTextureSubImage2D(
+ texture.handle, mip_map, 0, 0, static_cast<GLsizei>(params.MipWidth(mip_map)),
+ static_cast<GLsizei>(params.MipHeight(mip_map)), tuple.internal_format, image_size,
+ &gl_buffer[mip_map][buffer_offset]);
break;
case SurfaceTarget::Texture3D:
- glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
- static_cast<GLsizei>(params.MipWidth(mip_map)),
- static_cast<GLsizei>(params.MipHeight(mip_map)),
- static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size,
- &gl_buffer[mip_map][buffer_offset]);
+ glCompressedTextureSubImage3D(
+ texture.handle, mip_map, 0, 0, 0, static_cast<GLsizei>(params.MipWidth(mip_map)),
+ static_cast<GLsizei>(params.MipHeight(mip_map)),
+ static_cast<GLsizei>(params.MipDepth(mip_map)), tuple.internal_format, image_size,
+ &gl_buffer[mip_map][buffer_offset]);
break;
case SurfaceTarget::Texture2DArray:
case SurfaceTarget::TextureCubeArray:
- glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
- static_cast<GLsizei>(params.MipWidth(mip_map)),
- static_cast<GLsizei>(params.MipHeight(mip_map)),
- static_cast<GLsizei>(params.depth), 0, image_size,
- &gl_buffer[mip_map][buffer_offset]);
+ glCompressedTextureSubImage3D(
+ texture.handle, mip_map, 0, 0, 0, static_cast<GLsizei>(params.MipWidth(mip_map)),
+ static_cast<GLsizei>(params.MipHeight(mip_map)), static_cast<GLsizei>(params.depth),
+ tuple.internal_format, image_size, &gl_buffer[mip_map][buffer_offset]);
break;
case SurfaceTarget::TextureCubemap: {
- GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
+ const auto layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
for (std::size_t face = 0; face < params.depth; ++face) {
- glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face),
- mip_map, tuple.internal_format,
- static_cast<GLsizei>(params.MipWidth(mip_map)),
- static_cast<GLsizei>(params.MipHeight(mip_map)), 0,
- layer_size, &gl_buffer[mip_map][buffer_offset]);
+ glCompressedTextureSubImage3D(
+ texture.handle, mip_map, 0, 0, static_cast<GLint>(face),
+ static_cast<GLsizei>(params.MipWidth(mip_map)),
+ static_cast<GLsizei>(params.MipHeight(mip_map)), 1, tuple.internal_format,
+ layer_size, &gl_buffer[mip_map][buffer_offset]);
buffer_offset += layer_size;
}
break;
@@ -816,46 +788,43 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
static_cast<u32>(params.target));
UNREACHABLE();
- glCompressedTexImage2D(GL_TEXTURE_2D, mip_map, tuple.internal_format,
- static_cast<GLsizei>(params.MipWidth(mip_map)),
- static_cast<GLsizei>(params.MipHeight(mip_map)), 0,
- static_cast<GLsizei>(params.size_in_bytes_gl),
- &gl_buffer[mip_map][buffer_offset]);
+ glCompressedTextureSubImage2D(
+ texture.handle, mip_map, 0, 0, static_cast<GLsizei>(params.MipWidth(mip_map)),
+ static_cast<GLsizei>(params.MipHeight(mip_map)), tuple.internal_format,
+ static_cast<GLsizei>(params.size_in_bytes_gl), &gl_buffer[mip_map][buffer_offset]);
}
} else {
-
switch (params.target) {
case SurfaceTarget::Texture1D:
- glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,
- static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
- &gl_buffer[mip_map][buffer_offset]);
+ glTextureSubImage1D(texture.handle, mip_map, x0, static_cast<GLsizei>(rect.GetWidth()),
+ tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
break;
case SurfaceTarget::Texture2D:
- glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,
- static_cast<GLsizei>(rect.GetWidth()),
- static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
- &gl_buffer[mip_map][buffer_offset]);
+ glTextureSubImage2D(texture.handle, mip_map, x0, y0,
+ static_cast<GLsizei>(rect.GetWidth()),
+ static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
+ &gl_buffer[mip_map][buffer_offset]);
break;
case SurfaceTarget::Texture3D:
- glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
- static_cast<GLsizei>(rect.GetWidth()),
- static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
- tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
+ glTextureSubImage3D(texture.handle, mip_map, x0, y0, 0,
+ static_cast<GLsizei>(rect.GetWidth()),
+ static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
+ tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
break;
case SurfaceTarget::Texture2DArray:
case SurfaceTarget::TextureCubeArray:
- glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
- static_cast<GLsizei>(rect.GetWidth()),
- static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
- tuple.type, &gl_buffer[mip_map][buffer_offset]);
+ glTextureSubImage3D(texture.handle, mip_map, x0, y0, 0,
+ static_cast<GLsizei>(rect.GetWidth()),
+ static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
+ tuple.type, &gl_buffer[mip_map][buffer_offset]);
break;
case SurfaceTarget::TextureCubemap: {
std::size_t start = buffer_offset;
for (std::size_t face = 0; face < params.depth; ++face) {
- glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map,
- x0, y0, static_cast<GLsizei>(rect.GetWidth()),
- static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
- &gl_buffer[mip_map][buffer_offset]);
+ glTextureSubImage3D(texture.handle, mip_map, x0, y0, static_cast<GLint>(face),
+ static_cast<GLsizei>(rect.GetWidth()),
+ static_cast<GLsizei>(rect.GetHeight()), 1, tuple.format,
+ tuple.type, &gl_buffer[mip_map][buffer_offset]);
buffer_offset += params.LayerSizeGL(mip_map);
}
break;
@@ -864,9 +833,10 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}",
static_cast<u32>(params.target));
UNREACHABLE();
- glTexSubImage2D(GL_TEXTURE_2D, mip_map, x0, y0, static_cast<GLsizei>(rect.GetWidth()),
- static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
- &gl_buffer[mip_map][buffer_offset]);
+ glTextureSubImage2D(texture.handle, mip_map, x0, y0,
+ static_cast<GLsizei>(rect.GetWidth()),
+ static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
+ &gl_buffer[mip_map][buffer_offset]);
}
}
@@ -876,29 +846,18 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
void CachedSurface::EnsureTextureView() {
if (texture_view.handle != 0)
return;
- // Compressed texture are not being created with immutable storage
- UNIMPLEMENTED_IF(gl_is_compressed);
const GLenum target{TargetLayer()};
const GLuint num_layers{target == GL_TEXTURE_CUBE_MAP_ARRAY ? 6u : 1u};
constexpr GLuint min_layer = 0;
constexpr GLuint min_level = 0;
- texture_view.Create();
- glTextureView(texture_view.handle, target, texture.handle, gl_internal_format, min_level,
- params.max_mip_level, min_layer, num_layers);
-
- OpenGLState cur_state = OpenGLState::GetCurState();
- const auto& old_tex = cur_state.texture_units[0];
- SCOPE_EXIT({
- cur_state.texture_units[0] = old_tex;
- cur_state.Apply();
- });
- cur_state.texture_units[0].texture = texture_view.handle;
- cur_state.texture_units[0].target = target;
- cur_state.Apply();
-
- ApplyTextureDefaults(target, params.max_mip_level);
+ glGenTextures(1, &texture_view.handle);
+ glTextureView(texture_view.handle, target, texture.handle, gl_internal_format, 0,
+ params.max_mip_level, 0, 1);
+ ApplyTextureDefaults(texture_view.handle, params.max_mip_level);
+ glTextureParameteriv(texture_view.handle, GL_TEXTURE_SWIZZLE_RGBA,
+ reinterpret_cast<const GLint*>(swizzle.data()));
}
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
@@ -909,6 +868,25 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle);
}
+void CachedSurface::UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x,
+ Tegra::Texture::SwizzleSource swizzle_y,
+ Tegra::Texture::SwizzleSource swizzle_z,
+ Tegra::Texture::SwizzleSource swizzle_w) {
+ const GLenum new_x = MaxwellToGL::SwizzleSource(swizzle_x);
+ const GLenum new_y = MaxwellToGL::SwizzleSource(swizzle_y);
+ const GLenum new_z = MaxwellToGL::SwizzleSource(swizzle_z);
+ const GLenum new_w = MaxwellToGL::SwizzleSource(swizzle_w);
+ if (swizzle[0] == new_x && swizzle[1] == new_y && swizzle[2] == new_z && swizzle[3] == new_w) {
+ return;
+ }
+ swizzle = {new_x, new_y, new_z, new_w};
+ const auto swizzle_data = reinterpret_cast<const GLint*>(swizzle.data());
+ glTextureParameteriv(texture.handle, GL_TEXTURE_SWIZZLE_RGBA, swizzle_data);
+ if (texture_view.handle != 0) {
+ glTextureParameteriv(texture_view.handle, GL_TEXTURE_SWIZZLE_RGBA, swizzle_data);
+ }
+}
+
RasterizerCacheOpenGL::RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer)
: RasterizerCache{rasterizer} {
read_framebuffer.Create();
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 8d7d6722c..490b8252e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -382,6 +382,11 @@ public:
// Upload data in gl_buffer to this surface's texture
void UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle);
+ void UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x,
+ Tegra::Texture::SwizzleSource swizzle_y,
+ Tegra::Texture::SwizzleSource swizzle_z,
+ Tegra::Texture::SwizzleSource swizzle_w);
+
private:
void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle);
@@ -393,8 +398,8 @@ private:
SurfaceParams params{};
GLenum gl_target{};
GLenum gl_internal_format{};
- bool gl_is_compressed{};
std::size_t cached_size_in_bytes{};
+ std::array<GLenum, 4> swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
};
class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
index 1da744158..4170cbd3c 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp
@@ -15,12 +15,12 @@ MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_R
namespace OpenGL {
-void OGLTexture::Create() {
+void OGLTexture::Create(GLenum target) {
if (handle != 0)
return;
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
- glGenTextures(1, &handle);
+ glCreateTextures(target, 1, &handle);
}
void OGLTexture::Release() {
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index e33f1e973..df76cbc4b 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -28,7 +28,7 @@ public:
}
/// Creates a new internal OpenGL resource and stores the handle
- void Create();
+ void Create(GLenum target);
/// Deletes the internal OpenGL resource
void Release();
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index b7ba59350..81af803bc 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -462,29 +462,35 @@ void OpenGLState::ApplyPolygonOffset() const {
}
void OpenGLState::ApplyTextures() const {
+ bool has_delta{};
+ std::size_t first{};
+ std::size_t last{};
+ std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> textures;
+
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
const auto& texture_unit = texture_units[i];
const auto& cur_state_texture_unit = cur_state.texture_units[i];
+ textures[i] = texture_unit.texture;
- if (texture_unit.texture != cur_state_texture_unit.texture) {
- glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum());
- glBindTexture(texture_unit.target, texture_unit.texture);
- }
- // Update the texture swizzle
- if (texture_unit.swizzle.r != cur_state_texture_unit.swizzle.r ||
- texture_unit.swizzle.g != cur_state_texture_unit.swizzle.g ||
- texture_unit.swizzle.b != cur_state_texture_unit.swizzle.b ||
- texture_unit.swizzle.a != cur_state_texture_unit.swizzle.a) {
- std::array<GLint, 4> mask = {texture_unit.swizzle.r, texture_unit.swizzle.g,
- texture_unit.swizzle.b, texture_unit.swizzle.a};
- glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
+ if (textures[i] != cur_state_texture_unit.texture) {
+ if (!has_delta) {
+ first = i;
+ has_delta = true;
+ }
+ last = i;
}
}
+
+ if (has_delta) {
+ glBindTextures(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
+ textures.data());
+ }
}
void OpenGLState::ApplySamplers() const {
bool has_delta{};
- std::size_t first{}, last{};
+ std::size_t first{};
+ std::size_t last{};
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
for (std::size_t i = 0; i < std::size(samplers); ++i) {
samplers[i] = texture_units[i].sampler;
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index a5a7c0920..9e1eda5b1 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -126,26 +126,14 @@ public:
struct TextureUnit {
GLuint texture; // GL_TEXTURE_BINDING_2D
GLuint sampler; // GL_SAMPLER_BINDING
- GLenum target;
- struct {
- GLint r; // GL_TEXTURE_SWIZZLE_R
- GLint g; // GL_TEXTURE_SWIZZLE_G
- GLint b; // GL_TEXTURE_SWIZZLE_B
- GLint a; // GL_TEXTURE_SWIZZLE_A
- } swizzle;
void Unbind() {
texture = 0;
- swizzle.r = GL_RED;
- swizzle.g = GL_GREEN;
- swizzle.b = GL_BLUE;
- swizzle.a = GL_ALPHA;
}
void Reset() {
Unbind();
sampler = 0;
- target = GL_TEXTURE_2D;
}
};
std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index e37b65b38..5b09c38ea 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -171,10 +171,6 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
Memory::GetPointer(framebuffer_addr),
gl_framebuffer_data.data(), true);
- state.texture_units[0].texture = screen_info.texture.resource.handle;
- state.Apply();
-
- glActiveTexture(GL_TEXTURE0);
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
// Update existing texture
@@ -182,14 +178,11 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
// they differ from the LCD resolution.
// TODO: Applications could theoretically crash yuzu here by specifying too large
// framebuffer sizes. We should make sure that this cannot happen.
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
- screen_info.texture.gl_format, screen_info.texture.gl_type,
- gl_framebuffer_data.data());
+ glTextureSubImage2D(screen_info.texture.resource.handle, 0, 0, 0, framebuffer.width,
+ framebuffer.height, screen_info.texture.gl_format,
+ screen_info.texture.gl_type, gl_framebuffer_data.data());
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
-
- state.texture_units[0].texture = 0;
- state.Apply();
}
}
@@ -199,17 +192,8 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
*/
void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
const TextureInfo& texture) {
- state.texture_units[0].texture = texture.resource.handle;
- state.Apply();
-
- glActiveTexture(GL_TEXTURE0);
- u8 framebuffer_data[4] = {color_a, color_b, color_g, color_r};
-
- // Update existing texture
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data);
-
- state.texture_units[0].texture = 0;
- state.Apply();
+ const u8 framebuffer_data[4] = {color_a, color_b, color_g, color_r};
+ glClearTexImage(texture.resource.handle, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data);
}
/**
@@ -249,26 +233,13 @@ void RendererOpenGL::InitOpenGLObjects() {
sizeof(ScreenRectVertex));
// Allocate textures for the screen
- screen_info.texture.resource.Create();
+ screen_info.texture.resource.Create(GL_TEXTURE_2D);
- // Allocation of storage is deferred until the first frame, when we
- // know the framebuffer size.
-
- state.texture_units[0].texture = screen_info.texture.resource.handle;
- state.Apply();
-
- glActiveTexture(GL_TEXTURE0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ const GLuint texture = screen_info.texture.resource.handle;
+ glTextureStorage2D(texture, 1, GL_RGBA8, 1, 1);
screen_info.display_texture = screen_info.texture.resource.handle;
- state.texture_units[0].texture = 0;
- state.Apply();
-
// Clear screen to black
LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture);
}
@@ -284,20 +255,19 @@ void RendererOpenGL::CreateRasterizer() {
void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
const Tegra::FramebufferConfig& framebuffer) {
-
texture.width = framebuffer.width;
texture.height = framebuffer.height;
GLint internal_format;
switch (framebuffer.pixel_format) {
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
- internal_format = GL_RGBA;
+ internal_format = GL_RGBA8;
texture.gl_format = GL_RGBA;
texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
gl_framebuffer_data.resize(texture.width * texture.height * 4);
break;
default:
- internal_format = GL_RGBA;
+ internal_format = GL_RGBA8;
texture.gl_format = GL_RGBA;
texture.gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
gl_framebuffer_data.resize(texture.width * texture.height * 4);
@@ -306,15 +276,9 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
UNREACHABLE();
}
- state.texture_units[0].texture = texture.resource.handle;
- state.Apply();
-
- glActiveTexture(GL_TEXTURE0);
- glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
- texture.gl_format, texture.gl_type, nullptr);
-
- state.texture_units[0].texture = 0;
- state.Apply();
+ texture.resource.Release();
+ texture.resource.Create(GL_TEXTURE_2D);
+ glTextureStorage2D(texture.resource.handle, 1, internal_format, texture.width, texture.height);
}
void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x, float y, float w,
@@ -356,7 +320,6 @@ void RendererOpenGL::DrawScreenTriangles(const ScreenInfo& screen_info, float x,
}};
state.texture_units[0].texture = screen_info.display_texture;
- state.texture_units[0].swizzle = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
// Workaround brigthness problems in SMO by enabling sRGB in the final output
// if it has been used in the frame. Needed because of this bug in QT: QTBUG-50987
state.framebuffer_srgb.enabled = OpenGLState::GetsRGBUsed();
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp
index 4d075f088..3dd26da20 100644
--- a/src/video_core/shader/decode/memory.cpp
+++ b/src/video_core/shader/decode/memory.cpp
@@ -104,19 +104,42 @@ u32 ShaderIR::DecodeMemory(BasicBlock& bb, const BasicBlock& code, u32 pc) {
}
case OpCode::Id::LD_L: {
UNIMPLEMENTED_IF_MSG(instr.ld_l.unknown == 1, "LD_L Unhandled mode: {}",
- static_cast<unsigned>(instr.ld_l.unknown.Value()));
-
- const Node index = Operation(OperationCode::IAdd, GetRegister(instr.gpr8),
- Immediate(static_cast<s32>(instr.smem_imm)));
- const Node lmem = GetLocalMemory(index);
+ static_cast<u32>(instr.ld_l.unknown.Value()));
+
+ const auto GetLmem = [&](s32 offset) {
+ ASSERT(offset % 4 == 0);
+ const Node immediate_offset = Immediate(static_cast<s32>(instr.smem_imm) + offset);
+ const Node address = Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8),
+ immediate_offset);
+ return GetLocalMemory(address);
+ };
switch (instr.ldst_sl.type.Value()) {
- case Tegra::Shader::StoreType::Bytes32:
- SetRegister(bb, instr.gpr0, lmem);
+ case Tegra::Shader::StoreType::Bits32:
+ case Tegra::Shader::StoreType::Bits64:
+ case Tegra::Shader::StoreType::Bits128: {
+ const u32 count = [&]() {
+ switch (instr.ldst_sl.type.Value()) {
+ case Tegra::Shader::StoreType::Bits32:
+ return 1;
+ case Tegra::Shader::StoreType::Bits64:
+ return 2;
+ case Tegra::Shader::StoreType::Bits128:
+ return 4;
+ default:
+ UNREACHABLE();
+ return 0;
+ }
+ }();
+ for (u32 i = 0; i < count; ++i)
+ SetTemporal(bb, i, GetLmem(i * 4));
+ for (u32 i = 0; i < count; ++i)
+ SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i));
break;
+ }
default:
UNIMPLEMENTED_MSG("LD_L Unhandled type: {}",
- static_cast<unsigned>(instr.ldst_sl.type.Value()));
+ static_cast<u32>(instr.ldst_sl.type.Value()));
}
break;
}
@@ -202,12 +225,20 @@ u32 ShaderIR::DecodeMemory(BasicBlock& bb, const BasicBlock& code, u32 pc) {
UNIMPLEMENTED_IF_MSG(instr.st_l.unknown == 0, "ST_L Unhandled mode: {}",
static_cast<u32>(instr.st_l.unknown.Value()));
- const Node index = Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8),
- Immediate(static_cast<s32>(instr.smem_imm)));
+ const auto GetLmemAddr = [&](s32 offset) {
+ ASSERT(offset % 4 == 0);
+ const Node immediate = Immediate(static_cast<s32>(instr.smem_imm) + offset);
+ return Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8), immediate);
+ };
switch (instr.ldst_sl.type.Value()) {
- case Tegra::Shader::StoreType::Bytes32:
- SetLocalMemory(bb, index, GetRegister(instr.gpr0));
+ case Tegra::Shader::StoreType::Bits128:
+ SetLocalMemory(bb, GetLmemAddr(12), GetRegister(instr.gpr0.Value() + 3));
+ SetLocalMemory(bb, GetLmemAddr(8), GetRegister(instr.gpr0.Value() + 2));
+ case Tegra::Shader::StoreType::Bits64:
+ SetLocalMemory(bb, GetLmemAddr(4), GetRegister(instr.gpr0.Value() + 1));
+ case Tegra::Shader::StoreType::Bits32:
+ SetLocalMemory(bb, GetLmemAddr(0), GetRegister(instr.gpr0));
break;
default:
UNIMPLEMENTED_MSG("ST_L Unhandled type: {}",
@@ -324,15 +355,18 @@ u32 ShaderIR::DecodeMemory(BasicBlock& bb, const BasicBlock& code, u32 pc) {
const auto& sampler =
GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false);
+ u32 indexer = 0;
switch (instr.txq.query_type) {
case Tegra::Shader::TextureQueryType::Dimension: {
for (u32 element = 0; element < 4; ++element) {
- MetaTexture meta{sampler, element};
- const Node value = Operation(OperationCode::F4TextureQueryDimensions,
- std::move(meta), GetRegister(instr.gpr8));
- SetTemporal(bb, element, value);
+ if (instr.txq.IsComponentEnabled(element)) {
+ MetaTexture meta{sampler, element};
+ const Node value = Operation(OperationCode::F4TextureQueryDimensions,
+ std::move(meta), GetRegister(instr.gpr8));
+ SetTemporal(bb, indexer++, value);
+ }
}
- for (u32 i = 0; i < 4; ++i) {
+ for (u32 i = 0; i < indexer; ++i) {
SetRegister(bb, instr.gpr0.Value() + i, GetTemporal(i));
}
break;
@@ -734,4 +768,4 @@ std::tuple<std::size_t, std::size_t> ShaderIR::ValidateAndGetCoordinateElement(
return {coord_count, total_coord_count};
}
-} // namespace VideoCommon::Shader \ No newline at end of file
+} // namespace VideoCommon::Shader
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h
index 3f3cff652..0fc5530f2 100644
--- a/src/video_core/textures/texture.h
+++ b/src/video_core/textures/texture.h
@@ -182,7 +182,7 @@ struct TICEntry {
};
union {
BitField<0, 16, u32> height_minus_1;
- BitField<16, 15, u32> depth_minus_1;
+ BitField<16, 14, u32> depth_minus_1;
};
union {
BitField<6, 13, u32> mip_lod_bias;
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index 8290b4384..d21f95469 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -62,9 +62,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
const QColor new_bg_color = QColorDialog::getColor(bg_color);
if (!new_bg_color.isValid())
return;
- bg_color = new_bg_color;
- ui->bg_button->setStyleSheet(
- QString("QPushButton { background-color: %1 }").arg(bg_color.name()));
+ UpdateBackgroundColorButton(new_bg_color);
});
}
@@ -76,10 +74,8 @@ void ConfigureGraphics::setConfiguration() {
ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit);
ui->frame_limit->setValue(Settings::values.frame_limit);
ui->use_accurate_gpu_emulation->setChecked(Settings::values.use_accurate_gpu_emulation);
- bg_color = QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
- Settings::values.bg_blue);
- ui->bg_button->setStyleSheet(
- QString("QPushButton { background-color: %1 }").arg(bg_color.name()));
+ UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red, Settings::values.bg_green,
+ Settings::values.bg_blue));
}
void ConfigureGraphics::applyConfiguration() {
@@ -92,3 +88,13 @@ void ConfigureGraphics::applyConfiguration() {
Settings::values.bg_green = static_cast<float>(bg_color.greenF());
Settings::values.bg_blue = static_cast<float>(bg_color.blueF());
}
+
+void ConfigureGraphics::UpdateBackgroundColorButton(QColor color) {
+ bg_color = color;
+
+ QPixmap pixmap(ui->bg_button->size());
+ pixmap.fill(bg_color);
+
+ const QIcon color_icon(pixmap);
+ ui->bg_button->setIcon(color_icon);
+}
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index d6ffc6fde..f2799822d 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -23,6 +23,8 @@ public:
private:
void setConfiguration();
+ void UpdateBackgroundColorButton(QColor color);
+
std::unique_ptr<Ui::ConfigureGraphics> ui;
QColor bg_color;
};
diff --git a/src/yuzu/loading_screen.ui b/src/yuzu/loading_screen.ui
index a67d273fd..820b47536 100644
--- a/src/yuzu/loading_screen.ui
+++ b/src/yuzu/loading_screen.ui
@@ -132,7 +132,7 @@ border-radius: 15px;
font: 75 15pt &quot;Arial&quot;;</string>
</property>
<property name="text">
- <string>Stage 1 of 2. Estimate Time 5m 4s</string>
+ <string>Estimated Time 5m 4s</string>
</property>
</widget>
</item>
@@ -146,6 +146,9 @@ font: 75 15pt &quot;Arial&quot;;</string>
<property name="text">
<string/>
</property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
<property name="margin">
<number>30</number>
</property>
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index ab403b3ac..485e29de2 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1682,12 +1682,16 @@ void GMainWindow::OnToggleFilterBar() {
void GMainWindow::OnCaptureScreenshot() {
OnPauseGame();
- const QString path =
- QFileDialog::getSaveFileName(this, tr("Capture Screenshot"),
- UISettings::values.screenshot_path, tr("PNG Image (*.png)"));
- if (!path.isEmpty()) {
- UISettings::values.screenshot_path = QFileInfo(path).path();
- render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path);
+ QFileDialog png_dialog(this, tr("Capture Screenshot"), UISettings::values.screenshot_path,
+ tr("PNG Image (*.png)"));
+ png_dialog.setAcceptMode(QFileDialog::AcceptSave);
+ png_dialog.setDefaultSuffix("png");
+ if (png_dialog.exec()) {
+ const QString path = png_dialog.selectedFiles().first();
+ if (!path.isEmpty()) {
+ UISettings::values.screenshot_path = QFileInfo(path).path();
+ render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path);
+ }
}
OnStartGame();
}