Compare commits

...

15 Commits

Author SHA1 Message Date
Lioncash
c65713832c debug_utils: Remove unused includes
Quite a bit of these aren't necessary directly within the debug_utils
header and can be removed or included where actually necessary.
2018-08-24 20:49:14 -04:00
Lioncash
1e6a209649 debug_utils: Make BreakpointObserver class' constructor explicit
Avoids implicit conversions.
2018-08-24 20:49:14 -04:00
Lioncash
b6425c0511 debug_utils: Initialize active_breakpoint member of DebugContext
Ensures that all class members are initialized.
2018-08-24 20:15:50 -04:00
Tobias
165c23c848 Port #4013 from Citra: "Init logging sooner so we dont miss some logs on startup" (#1142)
* Port #4013 from Citra: "Init logging sooner so we dont miss some logs on startup"

* Fix compilation
2018-08-23 19:52:06 -04:00
David
5049ca5d8c Added GetBootMode (#1107)
* Added GetBootMode

Used by homebrew

* Added enum for GetBootMode
2018-08-23 18:31:45 -04:00
bunnei
0dce6d7008 Merge pull request #1160 from bunnei/surface-reserve
gl_rasterizer_cache: Several improvements
2018-08-23 12:04:37 -04:00
bunnei
3ed0115e36 Merge pull request #1153 from bunnei/stencil-clear
gl_rasterizer: Implement partial color clear, stencil clear, and stencil test.
2018-08-23 12:04:08 -04:00
bunnei
d65f079cc1 gl_rasterizer_cache: Blit when possible on RecreateSurface. 2018-08-23 11:27:01 -04:00
bunnei
fee8bdd90c gl_rasterizer_cache: Reserve surfaces that have already been created for later use. 2018-08-23 11:27:01 -04:00
bunnei
fde2017a3f gl_rasterizer_cache: Remove assert for RecreateSurface type. 2018-08-23 11:27:00 -04:00
bunnei
ebf5768340 gl_rasterizer_cache: Implement compressed texture copies. 2018-08-23 11:27:00 -04:00
bunnei
a4ac3bed6c gl_rasterizer: Implement stencil test.
- Used by Splatoon 2.
2018-08-23 11:08:49 -04:00
bunnei
da3da6be90 gl_rasterizer: Implement partial color clear and stencil clear. 2018-08-23 11:08:48 -04:00
bunnei
2a472ff54d maxwell_3d: Update to include additional stencil registers. 2018-08-23 11:08:47 -04:00
bunnei
c4ed0b16b1 gl_state: Update to handle stencil front/back face separately. 2018-08-23 11:08:46 -04:00
18 changed files with 322 additions and 127 deletions

View File

@@ -5,6 +5,7 @@
#pragma once
#include <array>
#include <map>
#include <memory>
#include <string>
#include <thread>

View File

@@ -18,6 +18,7 @@
#include "core/hle/service/apm/apm.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/nvflinger/nvflinger.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/set/set.h"
#include "core/settings.h"
@@ -309,7 +310,7 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
{5, &ICommonStateGetter::GetOperationMode, "GetOperationMode"},
{6, &ICommonStateGetter::GetPerformanceMode, "GetPerformanceMode"},
{7, nullptr, "GetCradleStatus"},
{8, nullptr, "GetBootMode"},
{8, &ICommonStateGetter::GetBootMode, "GetBootMode"},
{9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
{10, nullptr, "RequestToAcquireSleepLock"},
{11, nullptr, "ReleaseSleepLock"},
@@ -334,6 +335,15 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
event = Kernel::Event::Create(Kernel::ResetType::OneShot, "ICommonStateGetter:Event");
}
void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode
LOG_DEBUG(Service_AM, "called");
}
void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
event->Signal();

View File

@@ -116,6 +116,7 @@ private:
void GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx);
void GetOperationMode(Kernel::HLERequestContext& ctx);
void GetPerformanceMode(Kernel::HLERequestContext& ctx);
void GetBootMode(Kernel::HLERequestContext& ctx);
Kernel::SharedPtr<Kernel::Event> event;
};

View File

@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/hle/ipc_helpers.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/service.h"
namespace Service::PM {
@@ -10,11 +12,20 @@ class BootMode final : public ServiceFramework<BootMode> {
public:
explicit BootMode() : ServiceFramework{"pm:bm"} {
static const FunctionInfo functions[] = {
{0, nullptr, "GetBootMode"},
{0, &BootMode::GetBootMode, "GetBootMode"},
{1, nullptr, "SetMaintenanceBoot"},
};
RegisterHandlers(functions);
}
private:
void GetBootMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode
LOG_DEBUG(Service_PM, "called");
}
};
class DebugMonitor final : public ServiceFramework<DebugMonitor> {

View File

@@ -9,7 +9,7 @@ class ServiceManager;
}
namespace Service::PM {
enum class SystemBootMode : u32 { Normal = 0, Maintenance = 1 };
/// Registers all PM services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager);

View File

@@ -2,23 +2,8 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <algorithm>
#include <condition_variable>
#include <cstdint>
#include <cstring>
#include <fstream>
#include <map>
#include <mutex>
#include <string>
#include "common/assert.h"
#include "common/bit_field.h"
#include "common/color.h"
#include "common/common_types.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/vector_math.h"
#include "video_core/debug_utils/debug_utils.h"
namespace Tegra {

View File

@@ -4,19 +4,11 @@
#pragma once
#include <algorithm>
#include <array>
#include <condition_variable>
#include <iterator>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
#include <vector>
#include "common/common_types.h"
#include "common/vector_math.h"
namespace Tegra {
@@ -46,7 +38,7 @@ public:
class BreakPointObserver {
public:
/// Constructs the object such that it observes events of the given DebugContext.
BreakPointObserver(std::shared_ptr<DebugContext> debug_context)
explicit BreakPointObserver(std::shared_ptr<DebugContext> debug_context)
: context_weak(debug_context) {
std::unique_lock<std::mutex> lock(debug_context->breakpoint_mutex);
debug_context->breakpoint_observers.push_back(this);
@@ -141,8 +133,8 @@ public:
}
// TODO: Evaluate if access to these members should be hidden behind a public interface.
std::array<BreakPoint, (int)Event::NumEvents> breakpoints;
Event active_breakpoint;
std::array<BreakPoint, static_cast<int>(Event::NumEvents)> breakpoints;
Event active_breakpoint{};
bool at_breakpoint = false;
private:

View File

@@ -330,6 +330,17 @@ public:
Set = 0x150F,
};
enum class StencilOp : u32 {
Keep = 1,
Zero = 2,
Replace = 3,
Incr = 4,
Decr = 5,
Invert = 6,
IncrWrap = 7,
DecrWrap = 8,
};
struct Cull {
enum class FrontFace : u32 {
ClockWise = 0x0900,
@@ -508,8 +519,16 @@ public:
float clear_color[4];
float clear_depth;
INSERT_PADDING_WORDS(0x3);
s32 clear_stencil;
INSERT_PADDING_WORDS(0x93);
INSERT_PADDING_WORDS(0x6C);
s32 stencil_back_func_ref;
u32 stencil_back_mask;
u32 stencil_back_func_mask;
INSERT_PADDING_WORDS(0x20);
struct {
u32 address_high;
@@ -573,16 +592,14 @@ public:
u32 enable[NumRenderTargets];
} blend;
struct {
u32 enable;
u32 front_op_fail;
u32 front_op_zfail;
u32 front_op_zpass;
u32 front_func_func;
u32 front_func_ref;
u32 front_func_mask;
u32 front_mask;
} stencil;
u32 stencil_enable;
StencilOp stencil_front_op_fail;
StencilOp stencil_front_op_zfail;
StencilOp stencil_front_op_zpass;
ComparisonOp stencil_front_func_func;
s32 stencil_front_func_ref;
u32 stencil_front_func_mask;
u32 stencil_front_mask;
INSERT_PADDING_WORDS(0x3);
@@ -626,13 +643,11 @@ public:
INSERT_PADDING_WORDS(0x5);
struct {
u32 enable;
u32 back_op_fail;
u32 back_op_zfail;
u32 back_op_zpass;
u32 back_func_func;
} stencil_two_side;
u32 stencil_two_side_enable;
StencilOp stencil_back_op_fail;
StencilOp stencil_back_op_zfail;
StencilOp stencil_back_op_zpass;
ComparisonOp stencil_back_func_func;
INSERT_PADDING_WORDS(0x17);
@@ -944,6 +959,10 @@ ASSERT_REG_POSITION(viewport, 0x300);
ASSERT_REG_POSITION(vertex_buffer, 0x35D);
ASSERT_REG_POSITION(clear_color[0], 0x360);
ASSERT_REG_POSITION(clear_depth, 0x364);
ASSERT_REG_POSITION(clear_stencil, 0x368);
ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
ASSERT_REG_POSITION(zeta, 0x3F8);
ASSERT_REG_POSITION(vertex_attrib_format[0], 0x458);
ASSERT_REG_POSITION(rt_control, 0x487);
@@ -955,13 +974,24 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
ASSERT_REG_POSITION(depth_test_func, 0x4C3);
ASSERT_REG_POSITION(blend, 0x4CF);
ASSERT_REG_POSITION(stencil, 0x4E0);
ASSERT_REG_POSITION(stencil_enable, 0x4E0);
ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1);
ASSERT_REG_POSITION(stencil_front_op_zfail, 0x4E2);
ASSERT_REG_POSITION(stencil_front_op_zpass, 0x4E3);
ASSERT_REG_POSITION(stencil_front_func_func, 0x4E4);
ASSERT_REG_POSITION(stencil_front_func_ref, 0x4E5);
ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6);
ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
ASSERT_REG_POSITION(vb_element_base, 0x50D);
ASSERT_REG_POSITION(zeta_enable, 0x54E);
ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(tic, 0x55D);
ASSERT_REG_POSITION(stencil_two_side, 0x565);
ASSERT_REG_POSITION(stencil_two_side_enable, 0x565);
ASSERT_REG_POSITION(stencil_back_op_fail, 0x566);
ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567);
ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568);
ASSERT_REG_POSITION(stencil_back_func_func, 0x569);
ASSERT_REG_POSITION(point_coord_replace, 0x581);
ASSERT_REG_POSITION(code_address, 0x582);
ASSERT_REG_POSITION(draw, 0x585);

View File

@@ -14,6 +14,7 @@
#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/frontend/emu_window.h"
#include "core/hle/kernel/process.h"
@@ -315,16 +316,14 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c
using_color_fb = false;
}
// TODO(bunnei): Implement this
const bool has_stencil = false;
const bool has_stencil = regs.stencil_enable;
const bool write_color_fb =
state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE ||
state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE;
const bool write_depth_fb =
(state.depth.test_enabled && state.depth.write_mask == GL_TRUE) ||
(has_stencil && state.stencil.test_enabled && state.stencil.write_mask != 0);
(has_stencil && (state.stencil.front.write_mask || state.stencil.back.write_mask));
Surface color_surface;
Surface depth_surface;
@@ -364,41 +363,70 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c
}
void RasterizerOpenGL::Clear() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
const auto prev_state{state};
SCOPE_EXIT({ prev_state.Apply(); });
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
bool use_color_fb = false;
bool use_depth_fb = false;
GLbitfield clear_mask = 0;
if (regs.clear_buffers.R && regs.clear_buffers.G && regs.clear_buffers.B &&
OpenGLState clear_state;
clear_state.draw.draw_framebuffer = state.draw.draw_framebuffer;
clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
GLbitfield clear_mask{};
if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
regs.clear_buffers.A) {
clear_mask |= GL_COLOR_BUFFER_BIT;
use_color_fb = true;
if (regs.clear_buffers.RT == 0) {
// We only support clearing the first color attachment for now
clear_mask |= GL_COLOR_BUFFER_BIT;
use_color_fb = true;
} else {
// TODO(subv): Add support for the other color attachments
LOG_CRITICAL(HW_GPU, "Clear unimplemented for RT {}", regs.clear_buffers.RT);
}
}
if (regs.clear_buffers.Z) {
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!");
use_depth_fb = true;
clear_mask |= GL_DEPTH_BUFFER_BIT;
use_depth_fb = regs.zeta_enable != 0;
// Always enable the depth write when clearing the depth buffer. The depth write mask is
// ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true.
state.depth.test_enabled = true;
state.depth.write_mask = GL_TRUE;
state.depth.test_func = GL_ALWAYS;
state.Apply();
clear_state.depth.test_enabled = true;
clear_state.depth.test_func = GL_ALWAYS;
}
if (regs.clear_buffers.S) {
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!");
use_depth_fb = true;
clear_mask |= GL_STENCIL_BUFFER_BIT;
clear_state.stencil.test_enabled = true;
}
if (clear_mask == 0)
if (!use_color_fb && !use_depth_fb) {
// No color surface nor depth/stencil surface are enabled
return;
}
if (clear_mask == 0) {
// No clear mask is enabled
return;
}
ScopeAcquireGLContext acquire_context{emu_window};
auto [dirty_color_surface, dirty_depth_surface] =
ConfigureFramebuffers(use_color_fb, use_depth_fb, false);
// TODO(Subv): Support clearing only partial colors.
clear_state.Apply();
glClearColor(regs.clear_color[0], regs.clear_color[1], regs.clear_color[2],
regs.clear_color[3]);
glClearDepth(regs.clear_depth);
glClearStencil(regs.clear_stencil);
glClear(clear_mask);
@@ -451,6 +479,7 @@ void RasterizerOpenGL::DrawArrays() {
ConfigureFramebuffers(true, regs.zeta.Address() != 0 && regs.zeta_enable != 0, true);
SyncDepthTestState();
SyncStencilTestState();
SyncBlendState();
SyncLogicOpState();
SyncCullMode();
@@ -841,6 +870,34 @@ void RasterizerOpenGL::SyncDepthTestState() {
state.depth.test_func = MaxwellToGL::ComparisonOp(regs.depth_test_func);
}
void RasterizerOpenGL::SyncStencilTestState() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
state.stencil.test_enabled = regs.stencil_enable != 0;
if (!regs.stencil_enable) {
return;
}
// TODO(bunnei): Verify behavior when this is not set
ASSERT(regs.stencil_two_side_enable);
state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func);
state.stencil.front.test_ref = regs.stencil_front_func_ref;
state.stencil.front.test_mask = regs.stencil_front_func_mask;
state.stencil.front.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_fail);
state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail);
state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass);
state.stencil.front.write_mask = regs.stencil_front_mask;
state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func);
state.stencil.back.test_ref = regs.stencil_back_func_ref;
state.stencil.back.test_mask = regs.stencil_back_func_mask;
state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail);
state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail);
state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass);
state.stencil.back.write_mask = regs.stencil_back_mask;
}
void RasterizerOpenGL::SyncBlendState() {
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;

View File

@@ -141,6 +141,9 @@ private:
/// Syncs the depth test state to match the guest state
void SyncDepthTestState();
/// Syncs the stencil test state to match the guest state
void SyncStencilTestState();
/// Syncs the blend state to match the guest state
void SyncBlendState();

View File

@@ -780,17 +780,30 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
} else if (preserve_contents) {
// If surface parameters changed and we care about keeping the previous data, recreate
// the surface from the old one
return RecreateSurface(surface, params);
UnregisterSurface(surface);
Surface new_surface{RecreateSurface(surface, params)};
RegisterSurface(new_surface);
return new_surface;
} else {
// Delete the old surface before creating a new one to prevent collisions.
UnregisterSurface(surface);
}
}
// Try to get a previously reserved surface
surface = TryGetReservedSurface(params);
// No surface found - create a new one
surface = std::make_shared<CachedSurface>(params);
RegisterSurface(surface);
LoadSurface(surface);
if (!surface) {
surface = std::make_shared<CachedSurface>(params);
ReserveSurface(surface);
RegisterSurface(surface);
}
// Only load surface from memory if we care about the contents
if (preserve_contents) {
LoadSurface(surface);
}
return surface;
}
@@ -799,13 +812,18 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
const SurfaceParams& new_params) {
// Verify surface is compatible for blitting
const auto& params{surface->GetSurfaceParams()};
ASSERT(params.type == new_params.type);
ASSERT_MSG(params.GetCompressionFactor(params.pixel_format) == 1,
"Compressed texture reinterpretation is not supported");
// Create a new surface with the new parameters, and blit the previous surface to it
Surface new_surface{std::make_shared<CachedSurface>(new_params)};
// If format is unchanged, we can do a faster blit without reinterpreting pixel data
if (params.pixel_format == new_params.pixel_format) {
BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
new_surface->GetSurfaceParams().GetRect(), params.type,
read_framebuffer.handle, draw_framebuffer.handle);
return new_surface;
}
auto source_format = GetFormatTuple(params.pixel_format, params.component_type);
auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type);
@@ -818,9 +836,13 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
glGetTextureImage(surface->Texture().handle, 0, source_format.format, source_format.type,
params.SizeInBytes(), nullptr);
if (source_format.compressed) {
glGetCompressedTextureImage(surface->Texture().handle, 0,
static_cast<GLsizei>(params.SizeInBytes()), nullptr);
} else {
glGetTextureImage(surface->Texture().handle, 0, source_format.format, source_format.type,
static_cast<GLsizei>(params.SizeInBytes()), nullptr);
}
// If the new texture is bigger than the previous one, we need to fill in the rest with data
// from the CPU.
if (params.SizeInBytes() < new_params.SizeInBytes()) {
@@ -846,17 +868,21 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
const auto& dest_rect{new_params.GetRect()};
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle);
glTextureSubImage2D(
new_surface->Texture().handle, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, dest_format.type, nullptr);
if (dest_format.compressed) {
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
static_cast<GLsizei>(new_params.SizeInBytes()), nullptr);
} else {
glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0,
static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
dest_format.type, nullptr);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
pbo.Release();
// Update cache accordingly
UnregisterSurface(surface);
RegisterSurface(new_surface);
return new_surface;
}
@@ -931,6 +957,21 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
surface_cache.erase(search);
}
void RasterizerCacheOpenGL::ReserveSurface(const Surface& surface) {
const auto& surface_reserve_key{SurfaceReserveKey::Create(surface->GetSurfaceParams())};
surface_reserve[surface_reserve_key] = surface;
}
Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params) {
const auto& surface_reserve_key{SurfaceReserveKey::Create(params)};
auto search{surface_reserve.find(surface_reserve_key)};
if (search != surface_reserve.end()) {
RegisterSurface(search->second);
return search->second;
}
return {};
}
template <typename Map, typename Interval>
constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
return boost::make_iterator_range(map.equal_range(interval));

View File

@@ -11,6 +11,7 @@
#include <boost/icl/interval_map.hpp>
#include "common/common_types.h"
#include "common/hash.h"
#include "common/math_util.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
@@ -682,6 +683,27 @@ struct SurfaceParams {
u32 cache_height;
};
}; // namespace OpenGL
/// Hashable variation of SurfaceParams, used for a key in the surface cache
struct SurfaceReserveKey : Common::HashableStruct<OpenGL::SurfaceParams> {
static SurfaceReserveKey Create(const OpenGL::SurfaceParams& params) {
SurfaceReserveKey res;
res.state = params;
return res;
}
};
namespace std {
template <>
struct hash<SurfaceReserveKey> {
size_t operator()(const SurfaceReserveKey& k) const {
return k.Hash();
}
};
} // namespace std
namespace OpenGL {
class CachedSurface final {
public:
CachedSurface(const SurfaceParams& params);
@@ -752,12 +774,23 @@ private:
/// Remove surface from the cache
void UnregisterSurface(const Surface& surface);
/// Reserves a unique surface that can be reused later
void ReserveSurface(const Surface& surface);
/// Tries to get a reserved surface for the specified parameters
Surface TryGetReservedSurface(const SurfaceParams& params);
/// Increase/decrease the number of surface in pages touching the specified region
void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta);
std::unordered_map<Tegra::GPUVAddr, Surface> surface_cache;
PageMap cached_pages;
/// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
/// previously been used. This is to prevent surfaces from being constantly created and
/// destroyed when used with different surface parameters.
std::unordered_map<SurfaceReserveKey, Surface> surface_reserve;
OGLFramebuffer read_framebuffer;
OGLFramebuffer draw_framebuffer;
};

View File

@@ -27,13 +27,17 @@ OpenGLState::OpenGLState() {
color_mask.alpha_enabled = GL_TRUE;
stencil.test_enabled = false;
stencil.test_func = GL_ALWAYS;
stencil.test_ref = 0;
stencil.test_mask = 0xFF;
stencil.write_mask = 0xFF;
stencil.action_depth_fail = GL_KEEP;
stencil.action_depth_pass = GL_KEEP;
stencil.action_stencil_fail = GL_KEEP;
auto reset_stencil = [](auto& config) {
config.test_func = GL_ALWAYS;
config.test_ref = 0;
config.test_mask = 0xFFFFFFFF;
config.write_mask = 0xFFFFFFFF;
config.action_depth_fail = GL_KEEP;
config.action_depth_pass = GL_KEEP;
config.action_stencil_fail = GL_KEEP;
};
reset_stencil(stencil.front);
reset_stencil(stencil.back);
blend.enabled = true;
blend.rgb_equation = GL_FUNC_ADD;
@@ -129,24 +133,23 @@ void OpenGLState::Apply() const {
glDisable(GL_STENCIL_TEST);
}
}
if (stencil.test_func != cur_state.stencil.test_func ||
stencil.test_ref != cur_state.stencil.test_ref ||
stencil.test_mask != cur_state.stencil.test_mask) {
glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask);
}
if (stencil.action_depth_fail != cur_state.stencil.action_depth_fail ||
stencil.action_depth_pass != cur_state.stencil.action_depth_pass ||
stencil.action_stencil_fail != cur_state.stencil.action_stencil_fail) {
glStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail,
stencil.action_depth_pass);
}
// Stencil mask
if (stencil.write_mask != cur_state.stencil.write_mask) {
glStencilMask(stencil.write_mask);
}
auto config_stencil = [](GLenum face, const auto& config, const auto& prev_config) {
if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref ||
config.test_mask != prev_config.test_mask) {
glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
}
if (config.action_depth_fail != prev_config.action_depth_fail ||
config.action_depth_pass != prev_config.action_depth_pass ||
config.action_stencil_fail != prev_config.action_stencil_fail) {
glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
config.action_depth_pass);
}
if (config.write_mask != prev_config.write_mask) {
glStencilMaskSeparate(face, config.write_mask);
}
};
config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front);
config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
// Blending
if (blend.enabled != cur_state.blend.enabled) {

View File

@@ -58,14 +58,16 @@ public:
} color_mask; // GL_COLOR_WRITEMASK
struct {
bool test_enabled; // GL_STENCIL_TEST
GLenum test_func; // GL_STENCIL_FUNC
GLint test_ref; // GL_STENCIL_REF
GLuint test_mask; // GL_STENCIL_VALUE_MASK
GLuint write_mask; // GL_STENCIL_WRITEMASK
GLenum action_stencil_fail; // GL_STENCIL_FAIL
GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL
GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS
bool test_enabled; // GL_STENCIL_TEST
struct {
GLenum test_func; // GL_STENCIL_FUNC
GLint test_ref; // GL_STENCIL_REF
GLuint test_mask; // GL_STENCIL_VALUE_MASK
GLuint write_mask; // GL_STENCIL_WRITEMASK
GLenum action_stencil_fail; // GL_STENCIL_FAIL
GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL
GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS
} front, back;
} stencil;
struct {

View File

@@ -295,6 +295,30 @@ inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) {
return {};
}
inline GLenum StencilOp(Maxwell::StencilOp stencil) {
switch (stencil) {
case Maxwell::StencilOp::Keep:
return GL_KEEP;
case Maxwell::StencilOp::Zero:
return GL_ZERO;
case Maxwell::StencilOp::Replace:
return GL_REPLACE;
case Maxwell::StencilOp::Incr:
return GL_INCR;
case Maxwell::StencilOp::Decr:
return GL_DECR;
case Maxwell::StencilOp::Invert:
return GL_INVERT;
case Maxwell::StencilOp::IncrWrap:
return GL_INCR_WRAP;
case Maxwell::StencilOp::DecrWrap:
return GL_DECR_WRAP;
}
LOG_CRITICAL(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil));
UNREACHABLE();
return {};
}
inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) {
switch (front_face) {
case Maxwell::Cull::FrontFace::ClockWise:

View File

@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <map>
#include <QLabel>
#include <QMetaType>
#include <QPushButton>

View File

@@ -11,12 +11,13 @@
#include <QPushButton>
#include <QScrollArea>
#include <QSpinBox>
#include "common/vector_math.h"
#include "core/core.h"
#include "core/memory.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/gpu.h"
#include "video_core/textures/decoders.h"
#include "video_core/textures/texture.h"
#include "video_core/utils.h"
#include "yuzu/debugger/graphics/graphics_surface.h"
#include "yuzu/util/spinbox.h"

View File

@@ -91,9 +91,20 @@ void GMainWindow::ShowCallouts() {}
const int GMainWindow::max_recent_files_item;
static void InitializeLogging() {
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
FileUtil::CreateFullPath(log_dir);
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
}
GMainWindow::GMainWindow()
: config(new Config()), emu_thread(nullptr),
vfs(std::make_shared<FileSys::RealVfsFilesystem>()) {
InitializeLogging();
debug_context = Tegra::DebugContext::Construct();
@@ -1173,16 +1184,6 @@ void GMainWindow::UpdateUITheme() {
#undef main
#endif
static void InitializeLogging() {
Log::Filter log_filter;
log_filter.ParseFilterString(Settings::values.log_filter);
Log::SetGlobalFilter(log_filter);
const std::string& log_dir = FileUtil::GetUserPath(FileUtil::UserPath::LogDir);
FileUtil::CreateFullPath(log_dir);
Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE));
}
int main(int argc, char* argv[]) {
MicroProfileOnThreadCreate("Frontend");
SCOPE_EXIT({ MicroProfileShutdown(); });
@@ -1200,7 +1201,6 @@ int main(int argc, char* argv[]) {
GMainWindow main_window;
// After settings have been loaded by GMainWindow, apply the filter
InitializeLogging();
main_window.show();
return app.exec();
}