early-access version 1258
This commit is contained in:
parent
78b48028e1
commit
c7d8d0947d
18 changed files with 73 additions and 159 deletions
|
@ -1,7 +1,7 @@
|
|||
yuzu emulator early access
|
||||
=============
|
||||
|
||||
This is the source code for early-access 1255.
|
||||
This is the source code for early-access 1258.
|
||||
|
||||
## Legal Notice
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
#include "audio_core/info_updater.h"
|
||||
#include "audio_core/voice_context.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/writable_event.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
|
@ -71,10 +70,9 @@ namespace {
|
|||
namespace AudioCore {
|
||||
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
||||
AudioCommon::AudioRendererParameter params,
|
||||
std::shared_ptr<Kernel::WritableEvent> buffer_event_,
|
||||
Stream::ReleaseCallback&& release_callback,
|
||||
std::size_t instance_number)
|
||||
: worker_params{params}, buffer_event{buffer_event_},
|
||||
memory_pool_info(params.effect_count + params.voice_count * 4),
|
||||
: worker_params{params}, memory_pool_info(params.effect_count + params.voice_count * 4),
|
||||
voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
|
||||
sink_context(params.sink_count), splitter_context(),
|
||||
voices(params.voice_count), memory{memory_},
|
||||
|
@ -85,10 +83,9 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
|
|||
params.num_splitter_send_channels);
|
||||
mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count);
|
||||
audio_out = std::make_unique<AudioCore::AudioOut>();
|
||||
stream =
|
||||
audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
|
||||
fmt::format("AudioRenderer-Instance{}", instance_number),
|
||||
[=]() { buffer_event_->Signal(); });
|
||||
stream = audio_out->OpenStream(
|
||||
core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
|
||||
fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
|
||||
audio_out->StartStream(stream);
|
||||
|
||||
QueueMixedBuffer(0);
|
||||
|
|
|
@ -27,10 +27,6 @@ namespace Core::Timing {
|
|||
class CoreTiming;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class WritableEvent;
|
||||
}
|
||||
|
||||
namespace Core::Memory {
|
||||
class Memory;
|
||||
}
|
||||
|
@ -44,8 +40,7 @@ class AudioRenderer {
|
|||
public:
|
||||
AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
|
||||
AudioCommon::AudioRendererParameter params,
|
||||
std::shared_ptr<Kernel::WritableEvent> buffer_event_,
|
||||
std::size_t instance_number);
|
||||
Stream::ReleaseCallback&& release_callback, std::size_t instance_number);
|
||||
~AudioRenderer();
|
||||
|
||||
[[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
|
||||
|
@ -61,7 +56,6 @@ private:
|
|||
BehaviorInfo behavior_info{};
|
||||
|
||||
AudioCommon::AudioRendererParameter worker_params;
|
||||
std::shared_ptr<Kernel::WritableEvent> buffer_event;
|
||||
std::vector<ServerMemoryPoolInfo> memory_pool_info;
|
||||
VoiceContext voice_context;
|
||||
EffectContext effect_context;
|
||||
|
|
|
@ -132,6 +132,8 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count)
|
|||
for (std::size_t count = 0; count < max_count && !released_buffers.empty(); ++count) {
|
||||
if (released_buffers.front()) {
|
||||
tags.push_back(released_buffers.front()->GetTag());
|
||||
} else {
|
||||
ASSERT_MSG(false, "Invalid tag in released_buffers!");
|
||||
}
|
||||
released_buffers.pop();
|
||||
}
|
||||
|
@ -144,6 +146,8 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers() {
|
|||
while (!released_buffers.empty()) {
|
||||
if (released_buffers.front()) {
|
||||
tags.push_back(released_buffers.front()->GetTag());
|
||||
} else {
|
||||
ASSERT_MSG(false, "Invalid tag in released_buffers!");
|
||||
}
|
||||
released_buffers.pop();
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "common/assert.h"
|
||||
|
@ -35,7 +35,6 @@
|
|||
#include "core/hle/kernel/physical_core.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/kernel/service_thread.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/kernel/synchronization.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
@ -108,9 +107,6 @@ struct KernelCore::Impl {
|
|||
std::fill(register_host_thread_keys.begin(), register_host_thread_keys.end(),
|
||||
std::thread::id{});
|
||||
std::fill(register_host_thread_values.begin(), register_host_thread_values.end(), 0);
|
||||
|
||||
// Ensures all service threads gracefully shutdown
|
||||
service_threads.clear();
|
||||
}
|
||||
|
||||
void InitializePhysicalCores() {
|
||||
|
@ -349,9 +345,6 @@ struct KernelCore::Impl {
|
|||
std::shared_ptr<Kernel::SharedMemory> irs_shared_mem;
|
||||
std::shared_ptr<Kernel::SharedMemory> time_shared_mem;
|
||||
|
||||
// Threads used for services
|
||||
std::unordered_set<std::shared_ptr<Kernel::ServiceThread>> service_threads;
|
||||
|
||||
std::array<std::shared_ptr<Thread>, Core::Hardware::NUM_CPU_CORES> suspend_threads{};
|
||||
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
|
||||
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
|
||||
|
@ -646,16 +639,4 @@ void KernelCore::ExitSVCProfile() {
|
|||
MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]);
|
||||
}
|
||||
|
||||
std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
|
||||
auto service_thread = std::make_shared<Kernel::ServiceThread>(*this, 1, name);
|
||||
impl->service_threads.emplace(service_thread);
|
||||
return service_thread;
|
||||
}
|
||||
|
||||
void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
|
||||
if (auto strong_ptr = service_thread.lock()) {
|
||||
impl->service_threads.erase(strong_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -42,7 +42,6 @@ class Process;
|
|||
class ResourceLimit;
|
||||
class KScheduler;
|
||||
class SharedMemory;
|
||||
class ServiceThread;
|
||||
class Synchronization;
|
||||
class Thread;
|
||||
class TimeManager;
|
||||
|
@ -228,22 +227,6 @@ public:
|
|||
|
||||
void ExitSVCProfile();
|
||||
|
||||
/**
|
||||
* Creates an HLE service thread, which are used to execute service routines asynchronously.
|
||||
* While these are allocated per ServerSession, these need to be owned and managed outside of
|
||||
* ServerSession to avoid a circular dependency.
|
||||
* @param name String name for the ServerSession creating this thread, used for debug purposes.
|
||||
* @returns The a weak pointer newly created service thread.
|
||||
*/
|
||||
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
|
||||
|
||||
/**
|
||||
* Releases a HLE service thread, instructing KernelCore to free it. This should be called when
|
||||
* the ServerSession associated with the thread is destroyed.
|
||||
* @param service_thread Service thread to release.
|
||||
*/
|
||||
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
|
||||
|
||||
private:
|
||||
friend class Object;
|
||||
friend class Process;
|
||||
|
|
|
@ -25,10 +25,7 @@
|
|||
namespace Kernel {
|
||||
|
||||
ServerSession::ServerSession(KernelCore& kernel) : SynchronizationObject{kernel} {}
|
||||
|
||||
ServerSession::~ServerSession() {
|
||||
kernel.ReleaseServiceThread(service_thread);
|
||||
}
|
||||
ServerSession::~ServerSession() = default;
|
||||
|
||||
ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kernel,
|
||||
std::shared_ptr<Session> parent,
|
||||
|
@ -37,7 +34,7 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern
|
|||
|
||||
session->name = std::move(name);
|
||||
session->parent = std::move(parent);
|
||||
session->service_thread = kernel.CreateServiceThread(session->name);
|
||||
session->service_thread = std::make_unique<ServiceThread>(kernel, 1);
|
||||
|
||||
return MakeResult(std::move(session));
|
||||
}
|
||||
|
@ -142,11 +139,7 @@ ResultCode ServerSession::QueueSyncRequest(std::shared_ptr<Thread> thread,
|
|||
std::make_shared<HLERequestContext>(kernel, memory, SharedFrom(this), std::move(thread));
|
||||
|
||||
context->PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
|
||||
|
||||
if (auto strong_ptr = service_thread.lock()) {
|
||||
strong_ptr->QueueSyncRequest(*this, std::move(context));
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
service_thread->QueueSyncRequest(*this, std::move(context));
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ private:
|
|||
std::string name;
|
||||
|
||||
/// Thread to dispatch service requests
|
||||
std::weak_ptr<ServiceThread> service_thread;
|
||||
std::unique_ptr<ServiceThread> service_thread;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "common/assert.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
|
@ -23,7 +22,7 @@ namespace Kernel {
|
|||
|
||||
class ServiceThread::Impl final {
|
||||
public:
|
||||
explicit Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name);
|
||||
explicit Impl(KernelCore& kernel, std::size_t num_threads);
|
||||
~Impl();
|
||||
|
||||
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
|
||||
|
@ -33,17 +32,12 @@ private:
|
|||
std::queue<std::function<void()>> requests;
|
||||
std::mutex queue_mutex;
|
||||
std::condition_variable condition;
|
||||
const std::string service_name;
|
||||
bool stop{};
|
||||
};
|
||||
|
||||
ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std::string& name)
|
||||
: service_name{name} {
|
||||
|
||||
ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads) {
|
||||
for (std::size_t i = 0; i < num_threads; ++i)
|
||||
threads.emplace_back([this, &kernel] {
|
||||
Common::SetCurrentThreadName(std::string{"Hle_" + service_name}.c_str());
|
||||
|
||||
threads.emplace_back([&] {
|
||||
// Wait for first request before trying to acquire a render context
|
||||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
|
@ -58,7 +52,7 @@ ServiceThread::Impl::Impl(KernelCore& kernel, std::size_t num_threads, const std
|
|||
{
|
||||
std::unique_lock lock{queue_mutex};
|
||||
condition.wait(lock, [this] { return stop || !requests.empty(); });
|
||||
if (stop || requests.empty()) {
|
||||
if (stop && requests.empty()) {
|
||||
return;
|
||||
}
|
||||
task = std::move(requests.front());
|
||||
|
@ -93,8 +87,8 @@ ServiceThread::Impl::~Impl() {
|
|||
}
|
||||
}
|
||||
|
||||
ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_thread, const std::string& name)
|
||||
: impl{std::make_unique<Impl>(kernel, num_thread, name)} {}
|
||||
ServiceThread::ServiceThread(KernelCore& kernel, std::size_t num_threads)
|
||||
: impl{std::make_unique<Impl>(kernel, num_threads)} {}
|
||||
|
||||
ServiceThread::~ServiceThread() = default;
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
@ -15,7 +14,7 @@ class ServerSession;
|
|||
|
||||
class ServiceThread final {
|
||||
public:
|
||||
explicit ServiceThread(KernelCore& kernel, std::size_t num_threads, const std::string& name);
|
||||
explicit ServiceThread(KernelCore& kernel, std::size_t num_threads);
|
||||
~ServiceThread();
|
||||
|
||||
void QueueSyncRequest(ServerSession& session, std::shared_ptr<HLERequestContext>&& context);
|
||||
|
|
|
@ -70,8 +70,10 @@ public:
|
|||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioOutBufferReleased");
|
||||
|
||||
stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
|
||||
audio_params.channel_count, std::move(unique_name),
|
||||
[this] { buffer_event.writable->Signal(); });
|
||||
audio_params.channel_count, std::move(unique_name), [this] {
|
||||
const auto guard = LockService();
|
||||
buffer_event.writable->Signal();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -49,16 +49,16 @@ public:
|
|||
|
||||
system_event =
|
||||
Kernel::WritableEvent::CreateEventPair(system.Kernel(), "IAudioRenderer:SystemEvent");
|
||||
renderer = std::make_unique<AudioCore::AudioRenderer>(system.CoreTiming(), system.Memory(),
|
||||
audren_params, system_event.writable,
|
||||
instance_number);
|
||||
renderer = std::make_unique<AudioCore::AudioRenderer>(
|
||||
system.CoreTiming(), system.Memory(), audren_params,
|
||||
[this]() {
|
||||
const auto guard = LockService();
|
||||
system_event.writable->Signal();
|
||||
},
|
||||
instance_number);
|
||||
}
|
||||
|
||||
private:
|
||||
void UpdateAudioCallback() {
|
||||
system_event.writable->Signal();
|
||||
}
|
||||
|
||||
void GetSampleRate(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
|
|
|
@ -78,11 +78,13 @@ IAppletResource::IAppletResource(Core::System& system_)
|
|||
pad_update_event = Core::Timing::CreateEvent(
|
||||
"HID::UpdatePadCallback",
|
||||
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
const auto guard = LockService();
|
||||
UpdateControllers(user_data, ns_late);
|
||||
});
|
||||
motion_update_event = Core::Timing::CreateEvent(
|
||||
"HID::MotionPadCallback",
|
||||
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
|
||||
const auto guard = LockService();
|
||||
UpdateMotion(user_data, ns_late);
|
||||
});
|
||||
|
||||
|
|
|
@ -95,9 +95,14 @@ ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* se
|
|||
: system{system_}, service_name{service_name_}, max_sessions{max_sessions_},
|
||||
handler_invoker{handler_invoker_} {}
|
||||
|
||||
ServiceFrameworkBase::~ServiceFrameworkBase() = default;
|
||||
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||
// Wait for other threads to release access before destroying
|
||||
const auto guard = LockService();
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) {
|
||||
const auto guard = LockService();
|
||||
|
||||
ASSERT(!port_installed);
|
||||
|
||||
auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap();
|
||||
|
@ -106,6 +111,8 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager)
|
|||
}
|
||||
|
||||
void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
|
||||
const auto guard = LockService();
|
||||
|
||||
ASSERT(!port_installed);
|
||||
|
||||
auto [server_port, client_port] =
|
||||
|
@ -115,17 +122,6 @@ void ServiceFrameworkBase::InstallAsNamedPort(Kernel::KernelCore& kernel) {
|
|||
port_installed = true;
|
||||
}
|
||||
|
||||
std::shared_ptr<Kernel::ClientPort> ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel) {
|
||||
ASSERT(!port_installed);
|
||||
|
||||
auto [server_port, client_port] =
|
||||
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, service_name);
|
||||
auto port = MakeResult(std::move(server_port)).Unwrap();
|
||||
port->SetHleHandler(shared_from_this());
|
||||
port_installed = true;
|
||||
return client_port;
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
|
||||
handlers.reserve(handlers.size() + n);
|
||||
for (std::size_t i = 0; i < n; ++i) {
|
||||
|
@ -164,6 +160,8 @@ void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
|
|||
}
|
||||
|
||||
ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& context) {
|
||||
const auto guard = LockService();
|
||||
|
||||
switch (context.GetCommandType()) {
|
||||
case IPC::CommandType::Close: {
|
||||
IPC::ResponseBuilder rb{context, 2};
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/spin_lock.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
|
@ -68,11 +70,9 @@ public:
|
|||
void InstallAsService(SM::ServiceManager& service_manager);
|
||||
/// Creates a port pair and registers it on the kernel's global port registry.
|
||||
void InstallAsNamedPort(Kernel::KernelCore& kernel);
|
||||
/// Creates and returns an unregistered port for the service.
|
||||
std::shared_ptr<Kernel::ClientPort> CreatePort(Kernel::KernelCore& kernel);
|
||||
|
||||
/// Invokes a service request routine.
|
||||
void InvokeRequest(Kernel::HLERequestContext& ctx);
|
||||
|
||||
/// Handles a synchronization request for the service.
|
||||
ResultCode HandleSyncRequest(Kernel::HLERequestContext& context) override;
|
||||
|
||||
protected:
|
||||
|
@ -80,6 +80,11 @@ protected:
|
|||
template <typename Self>
|
||||
using HandlerFnP = void (Self::*)(Kernel::HLERequestContext&);
|
||||
|
||||
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||
[[nodiscard]] std::scoped_lock<Common::SpinLock> LockService() {
|
||||
return std::scoped_lock{lock_service};
|
||||
}
|
||||
|
||||
/// System context that the service operates under.
|
||||
Core::System& system;
|
||||
|
||||
|
@ -115,6 +120,9 @@ private:
|
|||
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
||||
InvokerFn* handler_invoker;
|
||||
boost::container::flat_map<u32, FunctionInfoBase> handlers;
|
||||
|
||||
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||
Common::SpinLock lock_service;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -186,18 +186,18 @@ void RendererOpenGL::LoadFBToScreenInfo(const Tegra::FramebufferConfig& framebuf
|
|||
// Reset the screen info's display texture to its own permanent texture
|
||||
screen_info.display_texture = screen_info.texture.resource.handle;
|
||||
|
||||
// TODO(Rodrigo): Read this from HLE
|
||||
constexpr u32 block_height_log2 = 4;
|
||||
const auto pixel_format{
|
||||
VideoCore::Surface::PixelFormatFromGPUPixelFormat(framebuffer.pixel_format)};
|
||||
const u32 bytes_per_pixel{VideoCore::Surface::BytesPerBlock(pixel_format)};
|
||||
const u64 size_in_bytes{framebuffer.stride * framebuffer.height * bytes_per_pixel};
|
||||
u8* const host_ptr{cpu_memory.GetPointer(framebuffer_addr)};
|
||||
rasterizer->FlushRegion(ToCacheAddr(host_ptr), size_in_bytes);
|
||||
|
||||
// TODO(Rodrigo): Read this from HLE
|
||||
constexpr u32 block_height_log2 = 4;
|
||||
Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, std::span<u8>(host_ptr, size_in_bytes),
|
||||
bytes_per_pixel, framebuffer.width, framebuffer.height, 1,
|
||||
block_height_log2, 0);
|
||||
const u64 size_in_bytes{Tegra::Texture::CalculateSize(
|
||||
true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
|
||||
const u8* const host_ptr{cpu_memory.GetPointer(framebuffer_addr)};
|
||||
const std::span<const u8> input_data(host_ptr, size_in_bytes);
|
||||
Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
|
||||
framebuffer.width, framebuffer.height, 1, block_height_log2,
|
||||
0);
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
|
||||
|
|
|
@ -116,19 +116,6 @@ constexpr std::array DYNAMIC_STATES{
|
|||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
};
|
||||
constexpr std::array EXTENDED_DYNAMIC_STATES{
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR,
|
||||
VK_DYNAMIC_STATE_CULL_MODE_EXT,
|
||||
VK_DYNAMIC_STATE_FRONT_FACE_EXT,
|
||||
VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT,
|
||||
VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
|
||||
VK_DYNAMIC_STATE_DEPTH_WRITE_ENABLE_EXT,
|
||||
VK_DYNAMIC_STATE_DEPTH_COMPARE_OP_EXT,
|
||||
VK_DYNAMIC_STATE_DEPTH_BOUNDS_TEST_ENABLE_EXT,
|
||||
VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT,
|
||||
VK_DYNAMIC_STATE_STENCIL_OP_EXT,
|
||||
};
|
||||
constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -136,13 +123,6 @@ constexpr VkPipelineDynamicStateCreateInfo PIPELINE_DYNAMIC_STATE_CREATE_INFO{
|
|||
.dynamicStateCount = static_cast<u32>(DYNAMIC_STATES.size()),
|
||||
.pDynamicStates = DYNAMIC_STATES.data(),
|
||||
};
|
||||
constexpr VkPipelineDynamicStateCreateInfo PIPELINE_EXTENDED_DYNAMIC_STATE_CREATE_INFO{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.dynamicStateCount = static_cast<u32>(EXTENDED_DYNAMIC_STATES.size()),
|
||||
.pDynamicStates = EXTENDED_DYNAMIC_STATES.data(),
|
||||
};
|
||||
constexpr VkPipelineColorBlendStateCreateInfo PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -309,7 +289,7 @@ void UpdateTwoTexturesDescriptorSet(const VKDevice& device, VkDescriptorSet desc
|
|||
device.GetLogical().UpdateDescriptorSets(write_descriptor_sets, nullptr);
|
||||
}
|
||||
|
||||
void BindBlitState(const VKDevice& device, vk::CommandBuffer cmdbuf, VkPipelineLayout layout,
|
||||
void BindBlitState(vk::CommandBuffer cmdbuf, VkPipelineLayout layout,
|
||||
const std::array<Offset2D, 2>& dst_region,
|
||||
const std::array<Offset2D, 2>& src_region) {
|
||||
const VkOffset2D offset{
|
||||
|
@ -341,22 +321,6 @@ void BindBlitState(const VKDevice& device, vk::CommandBuffer cmdbuf, VkPipelineL
|
|||
};
|
||||
cmdbuf.SetViewport(0, viewport);
|
||||
cmdbuf.SetScissor(0, scissor);
|
||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
||||
// Workaround bug on Nvidia's drivers where the state is not properly handled when switching
|
||||
// from one pipeline without dynamic state to one with.
|
||||
// To workaround the bug, we manually set the pipeline state as dynamic state and keep the
|
||||
// relevant bits enabled.
|
||||
cmdbuf.SetCullModeEXT(PIPELINE_RASTERIZATION_STATE_CREATE_INFO.cullMode);
|
||||
cmdbuf.SetFrontFaceEXT(PIPELINE_RASTERIZATION_STATE_CREATE_INFO.frontFace);
|
||||
cmdbuf.SetDepthTestEnableEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthTestEnable);
|
||||
cmdbuf.SetDepthWriteEnableEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthWriteEnable);
|
||||
cmdbuf.SetDepthCompareOpEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthCompareOp);
|
||||
cmdbuf.SetDepthBoundsTestEnableEXT(
|
||||
PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.depthBoundsTestEnable);
|
||||
cmdbuf.SetStencilTestEnableEXT(PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO.stencilTestEnable);
|
||||
cmdbuf.SetStencilOpEXT(VK_STENCIL_FACE_FRONT_AND_BACK, VK_STENCIL_OP_KEEP,
|
||||
VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_NEVER);
|
||||
}
|
||||
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_VERTEX_BIT, push_constants);
|
||||
}
|
||||
|
||||
|
@ -411,7 +375,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, const ImageV
|
|||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||
nullptr);
|
||||
BindBlitState(device, cmdbuf, layout, dst_region, src_region);
|
||||
BindBlitState(cmdbuf, layout, dst_region, src_region);
|
||||
cmdbuf.Draw(3, 1, 0, 0);
|
||||
});
|
||||
scheduler.InvalidateState();
|
||||
|
@ -440,7 +404,7 @@ void BlitImageHelper::BlitDepthStencil(const Framebuffer* dst_framebuffer,
|
|||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, layout, 0, descriptor_set,
|
||||
nullptr);
|
||||
BindBlitState(device, cmdbuf, layout, dst_region, src_region);
|
||||
BindBlitState(cmdbuf, layout, dst_region, src_region);
|
||||
cmdbuf.Draw(3, 1, 0, 0);
|
||||
});
|
||||
scheduler.InvalidateState();
|
||||
|
@ -562,9 +526,7 @@ VkPipeline BlitImageHelper::FindOrEmplacePipeline(const BlitImagePipelineKey& ke
|
|||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.pDepthStencilState = nullptr,
|
||||
.pColorBlendState = &color_blend_create_info,
|
||||
.pDynamicState = device.IsExtExtendedDynamicStateSupported()
|
||||
? &PIPELINE_EXTENDED_DYNAMIC_STATE_CREATE_INFO
|
||||
: &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.layout = *one_texture_pipeline_layout,
|
||||
.renderPass = key.renderpass,
|
||||
.subpass = 0,
|
||||
|
@ -593,9 +555,7 @@ VkPipeline BlitImageHelper::BlitDepthStencilPipeline(VkRenderPass renderpass) {
|
|||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.pDepthStencilState = &PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_EMPTY_CREATE_INFO,
|
||||
.pDynamicState = device.IsExtExtendedDynamicStateSupported()
|
||||
? &PIPELINE_EXTENDED_DYNAMIC_STATE_CREATE_INFO
|
||||
: &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.layout = *two_textures_pipeline_layout,
|
||||
.renderPass = renderpass,
|
||||
.subpass = 0,
|
||||
|
|
|
@ -477,14 +477,13 @@ void RasterizerVulkan::Draw(bool is_indexed, bool is_instanced) {
|
|||
return;
|
||||
}
|
||||
|
||||
UpdateDynamicStates();
|
||||
|
||||
buffer_bindings.Bind(device, scheduler);
|
||||
|
||||
BeginTransformFeedback();
|
||||
|
||||
scheduler.RequestRenderpass(framebuffer);
|
||||
scheduler.BindGraphicsPipeline(pipeline->GetHandle());
|
||||
UpdateDynamicStates();
|
||||
|
||||
const auto pipeline_layout = pipeline->GetLayout();
|
||||
const auto descriptor_set = pipeline->CommitDescriptorSet();
|
||||
|
|
Loading…
Reference in a new issue