early-access version 1258

This commit is contained in:
pineappleEA 2020-12-29 09:13:52 +00:00
parent 78b48028e1
commit c7d8d0947d
18 changed files with 73 additions and 159 deletions

View file

@ -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

View file

@ -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);

View file

@ -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;

View file

@ -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();
}

View file

@ -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

View file

@ -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;

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -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:

View file

@ -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,
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");

View file

@ -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);
});

View file

@ -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};

View file

@ -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;
};
/**

View file

@ -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));

View file

@ -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,

View file

@ -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();