From 239d2625e2f76afe2f437943962fa14165d2cc22 Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Tue, 14 Sep 2021 21:30:12 +0530 Subject: [PATCH] Introduce `CommandExecutor` + Implement `ClearBuffers` + More RT Formats This commit introduces the `CommandExecutor` which is responsible for creating and orchestrating a Vulkan command graph comprising of `CommandNode`s that construct all the objects required for rendering. As a result of the infrastructure provided by `CommandExecutor`, `ClearBuffers` could be implemented and be appropriately utilized. A bug regarding scissors was also determined and fixed in the PR, the extent of them were previously inaccurate and this has now been fixed. Note: We don't synchronize any textures from the guest for now as this would override the contents on the host, this'll be fixed with the appropriate write tracking but it also results in a black screen for anything that writes to FB --- app/CMakeLists.txt | 1 + .../gpu/interconnect/command_executor.cpp | 47 ++++ .../gpu/interconnect/command_executor.h | 31 +++ .../skyline/gpu/interconnect/command_nodes.h | 231 ++++++++++++++++++ .../graphics_context.h | 57 +++-- app/src/main/cpp/skyline/gpu/texture/format.h | 14 +- .../hosbinder/GraphicBufferProducer.cpp | 6 +- app/src/main/cpp/skyline/soc/gm20b.cpp | 5 +- app/src/main/cpp/skyline/soc/gm20b.h | 2 + .../skyline/soc/gm20b/engines/maxwell/types.h | 4 +- .../skyline/soc/gm20b/engines/maxwell_3d.cpp | 3 +- .../skyline/soc/gm20b/engines/maxwell_3d.h | 6 +- 12 files changed, 379 insertions(+), 28 deletions(-) create mode 100644 app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp create mode 100644 app/src/main/cpp/skyline/gpu/interconnect/command_executor.h create mode 100644 app/src/main/cpp/skyline/gpu/interconnect/command_nodes.h rename app/src/main/cpp/skyline/gpu/{context => interconnect}/graphics_context.h (77%) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 0944fe18..97748fb5 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -102,6 +102,7 @@ add_library(skyline SHARED ${source_DIR}/skyline/gpu/command_scheduler.cpp ${source_DIR}/skyline/gpu/texture/texture.cpp ${source_DIR}/skyline/gpu/presentation_engine.cpp + ${source_DIR}/skyline/gpu/interconnect/command_executor.cpp ${source_DIR}/skyline/soc/gm20b.cpp ${source_DIR}/skyline/soc/host1x/syncpoint.cpp ${source_DIR}/skyline/soc/gm20b/gpfifo.cpp diff --git a/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp new file mode 100644 index 00000000..836729b6 --- /dev/null +++ b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.cpp @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#include +#include "command_executor.h" + +namespace skyline::gpu::interconnect { + void CommandExecutor::AddSubpass(const std::function &, GPU &)> &function, vk::Rect2D renderArea, std::vector inputAttachments, std::vector colorAttachments, std::optional depthStencilAttachment) { + if (renderpass) { // TODO: Subpass support (&& renderpass->renderArea != renderArea) + nodes.emplace_back(std::in_place_type_t()); + renderpass = nullptr; + } + + bool newRenderpass{renderpass == nullptr}; + if (newRenderpass) + // We need to create a render pass if one doesn't already exist or the current one isn't compatible + renderpass = &std::get(nodes.emplace_back(std::in_place_type_t(), renderArea)); + + renderpass->AddSubpass(inputAttachments, colorAttachments, depthStencilAttachment); + if (newRenderpass) + nodes.emplace_back(std::in_place_type_t(), function); + else + nodes.emplace_back(std::in_place_type_t(), function); + } + + void CommandExecutor::Execute() { + if (!nodes.empty()) { + if (renderpass) { + nodes.emplace_back(std::in_place_type_t()); + renderpass = nullptr; + } + + gpu.scheduler.SubmitWithCycle([this](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &cycle) { + using namespace node; + for (NodeVariant &node : nodes) { + std::visit(VariantVisitor{ + [&](FunctionNode &node) { node(commandBuffer, cycle, gpu); }, + [&](RenderpassNode &node) { node(commandBuffer, cycle, gpu); }, + [&](RenderpassEndNode &node) { node(commandBuffer, cycle, gpu); }, + }, node); + } + }); + + nodes.clear(); + } + } +} diff --git a/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h new file mode 100644 index 00000000..8dc62e58 --- /dev/null +++ b/app/src/main/cpp/skyline/gpu/interconnect/command_executor.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include +#include "command_nodes.h" + +namespace skyline::gpu::interconnect { + /** + * @brief Assembles a Vulkan command stream with various nodes and manages execution of the produced graph + * @note This class is **NOT** thread-safe and should not be utilized by multiple threads concurrently + */ + class CommandExecutor { + private: + GPU &gpu; + boost::container::stable_vector nodes; + node::RenderpassNode *renderpass{}; + + public: + CommandExecutor(const DeviceState &state) : gpu(*state.gpu) {} + + /** + * @brief Adds a command that needs to be executed inside a subpass configured with certain attachments + * @note Any texture supplied to this **must** be locked by the calling thread, it should also undergo no persistent layout transitions till execution + */ + void AddSubpass(const std::function &, GPU &)> &function, vk::Rect2D renderArea, std::vector inputAttachments = {}, std::vector colorAttachments = {}, std::optional depthStencilAttachment = {}); + + void Execute(); + }; +} diff --git a/app/src/main/cpp/skyline/gpu/interconnect/command_nodes.h b/app/src/main/cpp/skyline/gpu/interconnect/command_nodes.h new file mode 100644 index 00000000..87c7dc24 --- /dev/null +++ b/app/src/main/cpp/skyline/gpu/interconnect/command_nodes.h @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) + +#pragma once + +#include + +namespace skyline::gpu::interconnect::node { + /** + * @brief A generic node for simply executing a function + */ + template &, GPU &)> + struct FunctionNodeBase { + std::function function; + + FunctionNodeBase(std::function function) : function(function) {} + + template + void operator()(Args &&... args) { + function(std::forward(args)...); + } + }; + + using FunctionNode = FunctionNodeBase<>; + + /** + * @brief Creates and begins a VkRenderpass while tying lifetimes of all bound resources to a GPU fence + */ + struct RenderpassNode { + private: + struct Storage : public FenceCycleDependency { + vk::raii::Device *device{}; + vk::Framebuffer framebuffer{}; + vk::RenderPass renderpass{}; + std::vector> textures; + + ~Storage() { + if (device) { + if (framebuffer) + (**device).destroy(framebuffer, nullptr, *device->getDispatcher()); + if (renderpass) + (**device).destroy(renderpass, nullptr, *device->getDispatcher()); + } + } + }; + std::shared_ptr storage; + + std::vector attachments; + std::vector attachmentDescriptions; + + std::vector attachmentReferences; + std::vector> preserveAttachmentReferences; //!< Any attachment that must be preserved to be utilized by a future subpass, these are stored per-subpass to ensure contiguity + + public: + std::vector subpassDescriptions; + std::vector subpassDependencies; + + vk::Rect2D renderArea; + std::vector clearValues; + + RenderpassNode(vk::Rect2D renderArea) : storage(std::make_shared()), renderArea(renderArea) {} + + /** + * @note Any preservation of attachments from previous subpasses is automatically handled by this + * @return The index of the attachment in the render pass which can be utilized with VkAttachmentReference + */ + u32 AddAttachment(TextureView &view) { + auto &textures{storage->textures}; + auto texture{std::find(textures.begin(), textures.end(), view.backing)}; + if (texture == textures.end()) + textures.push_back(view.backing); + + vk::AttachmentDescription attachmentDescription{ + .format = *view.format, + .initialLayout = view.backing->layout, + .finalLayout = view.backing->layout, + }; + + auto vkView{view.GetView()}; + auto attachment{std::find(attachments.begin(), attachments.end(), vkView)}; + if (attachment == attachments.end() || attachmentDescriptions[std::distance(attachments.begin(), attachment)] != attachmentDescription) { + // If we cannot find any matches for the specified attachment, we add it as a new one + attachments.push_back(vkView); + attachmentDescriptions.push_back(attachmentDescription); + return attachments.size() - 1; + } else { + // If we've got a match from a previous subpass, we need to preserve the attachment till the current subpass + auto attachmentIndex{std::distance(attachments.begin(), attachment)}; + auto attachmentReferenceIt{std::find_if(attachmentReferences.begin(), attachmentReferences.end(), [&](const vk::AttachmentReference &reference) { + return reference.attachment == attachmentIndex; + })}; + + auto attachmentReferenceOffset{std::distance(attachmentReferences.begin(), attachmentReferenceIt) * sizeof(vk::AttachmentReference)}; + auto subpassDescriptionIt{std::find_if(subpassDescriptions.begin(), subpassDescriptions.end(), [&](const vk::SubpassDescription &description) { + return reinterpret_cast(description.pDepthStencilAttachment) > attachmentReferenceOffset; + })}; + + for (ssize_t subpassIndex{std::distance(subpassDescriptions.begin(), subpassDescriptionIt)}; subpassIndex != subpassDescriptions.size(); subpassIndex++) + preserveAttachmentReferences[subpassIndex].push_back(attachmentIndex); + + return std::distance(attachments.begin(), attachment); + } + } + + void AddSubpass(std::vector &inputAttachments, std::vector &colorAttachments, std::optional &depthStencilAttachment) { + attachmentReferences.reserve(attachmentReferences.size() + inputAttachments.size() + colorAttachments.size() + (depthStencilAttachment ? 1 : 0)); + + auto inputAttachmentsOffset{attachmentReferences.size() * sizeof(vk::AttachmentReference)}; + for (auto &attachment : inputAttachments) { + attachmentReferences.push_back(vk::AttachmentReference{ + .attachment = AddAttachment(attachment), + .layout = attachment.backing->layout, + }); + } + + auto colorAttachmentsOffset{attachmentReferences.size() * sizeof(vk::AttachmentReference)}; + for (auto &attachment : colorAttachments) { + attachmentReferences.push_back(vk::AttachmentReference{ + .attachment = AddAttachment(attachment), + .layout = attachment.backing->layout, + }); + } + + auto depthStencilAttachmentOffset{attachmentReferences.size() * sizeof(vk::AttachmentReference)}; + if (depthStencilAttachment) { + attachmentReferences.push_back(vk::AttachmentReference{ + .attachment = AddAttachment(*depthStencilAttachment), + .layout = depthStencilAttachment->backing->layout, + }); + } + + preserveAttachmentReferences.emplace_back(); // We need to create storage for any attachments that might need to preserved by this pass + + // Note: We encode the offsets as the pointers due to vector pointer invalidation, the vector offset will be added to them prior to submission + subpassDescriptions.push_back(vk::SubpassDescription{ + .pipelineBindPoint = vk::PipelineBindPoint::eGraphics, + .inputAttachmentCount = static_cast(inputAttachments.size()), + .pInputAttachments = reinterpret_cast(inputAttachmentsOffset), + .colorAttachmentCount = static_cast(colorAttachments.size()), + .pColorAttachments = reinterpret_cast(colorAttachmentsOffset), + .pDepthStencilAttachment = reinterpret_cast(depthStencilAttachment ? depthStencilAttachmentOffset : std::numeric_limits::max()), + }); + } + + void operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &cycle, GPU &gpu) { + storage->device = &gpu.vkDevice; + + auto preserveAttachmentIt{preserveAttachmentReferences.begin()}; + auto attachmentReferenceOffset{reinterpret_cast(attachmentReferences.data())}; + for (auto &subpassDescription : subpassDescriptions) { + subpassDescription.pInputAttachments = reinterpret_cast(attachmentReferenceOffset + reinterpret_cast(subpassDescription.pInputAttachments)); + subpassDescription.pColorAttachments = reinterpret_cast(attachmentReferenceOffset + reinterpret_cast(subpassDescription.pColorAttachments)); + + auto depthStencilAttachmentOffset{reinterpret_cast(subpassDescription.pDepthStencilAttachment)}; + if (depthStencilAttachmentOffset != std::numeric_limits::max()) + subpassDescription.pDepthStencilAttachment = reinterpret_cast(attachmentReferenceOffset + depthStencilAttachmentOffset); + else + subpassDescription.pDepthStencilAttachment = nullptr; + + subpassDescription.preserveAttachmentCount = preserveAttachmentIt->size(); + subpassDescription.pPreserveAttachments = preserveAttachmentIt->data(); + preserveAttachmentIt++; + } + + for (auto &texture : storage->textures) { + texture->lock(); + texture->WaitOnBacking(); + if (texture->cycle != cycle) + texture->WaitOnFence(); + } + + auto renderpass{(*gpu.vkDevice).createRenderPass(vk::RenderPassCreateInfo{ + .attachmentCount = static_cast(attachmentDescriptions.size()), + .pAttachments = attachmentDescriptions.data(), + .subpassCount = static_cast(subpassDescriptions.size()), + .pSubpasses = subpassDescriptions.data(), + .dependencyCount = static_cast(subpassDependencies.size()), + .pDependencies = subpassDependencies.data(), + }, nullptr, *gpu.vkDevice.getDispatcher())}; + storage->renderpass = renderpass; + + auto framebuffer{(*gpu.vkDevice).createFramebuffer(vk::FramebufferCreateInfo{ + .renderPass = renderpass, + .attachmentCount = static_cast(attachments.size()), + .pAttachments = attachments.data(), + .width = renderArea.extent.width, + .height = renderArea.extent.height, + .layers = 1, + }, nullptr, *gpu.vkDevice.getDispatcher())}; + storage->framebuffer = framebuffer; + + commandBuffer.beginRenderPass(vk::RenderPassBeginInfo{ + .renderPass = renderpass, + .framebuffer = framebuffer, + .renderArea = renderArea, + .clearValueCount = static_cast(clearValues.size()), + .pClearValues = clearValues.data(), + }, vk::SubpassContents::eInline); + + cycle->AttachObjects(storage); + + for (auto &texture : storage->textures) { + texture->unlock(); + texture->cycle = cycle; + } + } + }; + + /** + * @brief A FunctionNode which progresses to the next subpass prior to calling the function + */ + struct NextSubpassNode : FunctionNode { + using FunctionNode::FunctionNode; + + void operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &cycle, GPU &gpu) { + commandBuffer.nextSubpass(vk::SubpassContents::eInline); + FunctionNode::operator()(commandBuffer, cycle, gpu); + } + }; + + /** + * @brief Ends a VkRenderpass that would be created prior with RenderpassNode + */ + struct RenderpassEndNode { + void operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &cycle, GPU &gpu) { + commandBuffer.endRenderPass(); + } + }; + + using NodeVariant = std::variant; //!< A variant encompassing all command nodes types +} diff --git a/app/src/main/cpp/skyline/gpu/context/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h similarity index 77% rename from app/src/main/cpp/skyline/gpu/context/graphics_context.h rename to app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index 40c07dba..7b811f61 100644 --- a/app/src/main/cpp/skyline/gpu/context/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -3,13 +3,12 @@ #pragma once -#include -#include #include #include #include +#include "command_executor.h" -namespace skyline::gpu::context { +namespace skyline::gpu::interconnect { namespace maxwell3d = soc::gm20b::engine::maxwell3d::type; /** @@ -20,6 +19,7 @@ namespace skyline::gpu::context { private: GPU &gpu; soc::gm20b::GMMU &gmmu; + gpu::interconnect::CommandExecutor &executor; struct RenderTarget { bool disabled{}; //!< If this RT has been disabled and will be an unbound attachment instead @@ -50,7 +50,7 @@ namespace skyline::gpu::context { public: - GraphicsContext(GPU &gpu, soc::gm20b::GMMU &gmmu) : gpu(gpu), gmmu(gmmu) { + GraphicsContext(GPU &gpu, soc::gm20b::GMMU &gmmu, gpu::interconnect::CommandExecutor &executor) : gpu(gpu), gmmu(gmmu), executor(executor) { scissors.fill(DefaultScissor); } @@ -88,8 +88,12 @@ namespace skyline::gpu::context { switch (format) { case maxwell3d::RenderTarget::ColorFormat::None: return {}; + case maxwell3d::RenderTarget::ColorFormat::A2B10G10R10Unorm: + return format::A2B10G10R10Unorm; case maxwell3d::RenderTarget::ColorFormat::R8G8B8A8Unorm: - return format::RGBA8888Unorm; + return format::R8G8B8A8Unorm; + case maxwell3d::RenderTarget::ColorFormat::A8B8G8R8Srgb: + return format::A8B8G8R8Srgb; default: throw exception("Cannot translate the supplied RT format: 0x{:X}", static_cast(format)); } @@ -148,7 +152,8 @@ namespace skyline::gpu::context { renderTarget.guest.mappings.assign(mappings.begin(), mappings.end()); } - return &*(renderTarget.view = gpu.texture.FindOrCreate(renderTarget.guest)); + renderTarget.view = gpu.texture.FindOrCreate(renderTarget.guest); + return &renderTarget.view.value(); } void UpdateRenderTargetControl(maxwell3d::RenderTargetControl control) { @@ -186,10 +191,34 @@ namespace skyline::gpu::context { } void ClearBuffers(maxwell3d::ClearBuffers clear) { - auto renderTarget{GetRenderTarget(renderTargetControl.Map(clear.renderTargetId))}; - if (renderTarget) { - std::lock_guard lock(*renderTarget->backing); - // TODO: Clear the buffer + auto renderTargetIndex{renderTargetControl[clear.renderTargetId]}; + auto renderTargetPointer{GetRenderTarget(renderTargetIndex)}; + if (renderTargetPointer) { + auto renderTarget{*renderTargetPointer}; + std::lock_guard lock(*renderTarget.backing); + + vk::ImageAspectFlags aspect{}; + if (clear.depth) + aspect |= vk::ImageAspectFlagBits::eDepth; + if (clear.stencil) + aspect |= vk::ImageAspectFlagBits::eStencil; + if (clear.red || clear.green || clear.blue || clear.alpha) + aspect |= vk::ImageAspectFlagBits::eColor; + aspect &= renderTarget.format->vkAspect; + + executor.AddSubpass([aspect = aspect, clearColorValue = clearColorValue, layerId = clear.layerId, scissor = scissors.at(renderTargetIndex)](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &, GPU &) { + commandBuffer.clearAttachments(vk::ClearAttachment{ + .aspectMask = aspect, + .colorAttachment = 0, + .clearValue = clearColorValue, + }, vk::ClearRect{ + .rect = scissor, + .baseArrayLayer = layerId, + .layerCount = 1, + }); + }, vk::Rect2D{ + .extent = renderTarget.backing->dimensions, + }, {}, {renderTarget}); } } @@ -198,22 +227,22 @@ namespace skyline::gpu::context { void SetScissor(size_t index, std::optional scissor) { scissors.at(index) = scissor ? vk::Rect2D{ .offset.x = scissor->horizontal.minimum, - .extent.width = scissor->horizontal.maximum, + .extent.width = static_cast(scissor->horizontal.maximum - scissor->horizontal.minimum), .offset.y = scissor->vertical.minimum, - .extent.height = scissor->horizontal.maximum, + .extent.height = static_cast(scissor->horizontal.maximum - scissor->vertical.minimum), } : DefaultScissor; } void SetScissorHorizontal(size_t index, maxwell3d::Scissor::ScissorBounds bounds) { auto &scissor{scissors.at(index)}; scissor.offset.x = bounds.minimum; - scissor.extent.width = bounds.maximum; + scissor.extent.width = bounds.maximum - bounds.minimum; } void SetScissorVertical(size_t index, maxwell3d::Scissor::ScissorBounds bounds) { auto &scissor{scissors.at(index)}; scissor.offset.y = bounds.minimum; - scissor.extent.height = bounds.maximum; + scissor.extent.height = bounds.maximum - bounds.minimum; } }; } diff --git a/app/src/main/cpp/skyline/gpu/texture/format.h b/app/src/main/cpp/skyline/gpu/texture/format.h index 198af2c2..85116991 100644 --- a/app/src/main/cpp/skyline/gpu/texture/format.h +++ b/app/src/main/cpp/skyline/gpu/texture/format.h @@ -10,8 +10,10 @@ namespace skyline::gpu::format { using vkf = vk::Format; using vka = vk::ImageAspectFlagBits; - constexpr Format RGBA8888Unorm{sizeof(u8) * 4, 1, 1, vkf::eR8G8B8A8Unorm, vka::eColor}; //!< 8-bits per channel 4-channel pixels - constexpr Format RGB565Unorm{sizeof(u8) * 2, 1, 1, vkf::eR5G6B5UnormPack16, vka::eColor}; //!< Red channel: 5-bit, Green channel: 6-bit, Blue channel: 5-bit + constexpr Format R8G8B8A8Unorm{sizeof(u32), 1, 1, vkf::eR8G8B8A8Unorm, vka::eColor}; + constexpr Format R5G6B5Unorm{sizeof(u16), 1, 1, vkf::eR5G6B5UnormPack16, vka::eColor}; + constexpr Format A2B10G10R10Unorm{sizeof(u32), 1, 1, vkf::eA2B10G10R10UnormPack32, vka::eColor}; + constexpr Format A8B8G8R8Srgb{sizeof(u32), 1, 1, vkf::eA8B8G8R8SrgbPack32, vka::eColor}; /** * @brief Converts a Vulkan format to a Skyline format @@ -19,9 +21,13 @@ namespace skyline::gpu::format { constexpr gpu::texture::Format GetFormat(vk::Format format) { switch (format) { case vk::Format::eR8G8B8A8Unorm: - return RGBA8888Unorm; + return R8G8B8A8Unorm; case vk::Format::eR5G6B5UnormPack16: - return RGB565Unorm; + return R5G6B5Unorm; + case vk::Format::eA2B10G10R10UnormPack32: + return A2B10G10R10Unorm; + case vk::Format::eA8B8G8R8SrgbPack32: + return A8B8G8R8Srgb; default: throw exception("Vulkan format not supported: '{}'", vk::to_string(format)); } diff --git a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp index 3bd03e10..eb2052b6 100644 --- a/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp +++ b/app/src/main/cpp/skyline/services/hosbinder/GraphicBufferProducer.cpp @@ -304,11 +304,11 @@ namespace skyline::service::hosbinder { switch (handle.format) { case AndroidPixelFormat::RGBA8888: case AndroidPixelFormat::RGBX8888: - format = gpu::format::RGBA8888Unorm; + format = gpu::format::R8G8B8A8Unorm; break; case AndroidPixelFormat::RGB565: - format = gpu::format::RGB565Unorm; + format = gpu::format::R5G6B5Unorm; break; default: @@ -386,7 +386,7 @@ namespace skyline::service::hosbinder { { auto &texture{buffer.texture}; std::scoped_lock textureLock(*texture); - texture->SynchronizeHost(); + // texture->SynchronizeHost(); u64 frameId; state.gpu->presentation.Present(texture, isAutoTimestamp ? 0 : timestamp, swapInterval, crop, scalingMode, transform, frameId); } diff --git a/app/src/main/cpp/skyline/soc/gm20b.cpp b/app/src/main/cpp/skyline/soc/gm20b.cpp index e945202e..206b8e8a 100644 --- a/app/src/main/cpp/skyline/soc/gm20b.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b.cpp @@ -7,8 +7,9 @@ namespace skyline::soc::gm20b { GM20B::GM20B(const DeviceState &state) : fermi2D(state), keplerMemory(state), - maxwell3D(state, gmmu), + maxwell3D(state, gmmu, executor), maxwellCompute(state), maxwellDma(state), - gpfifo(state) {} + gpfifo(state), + executor(state) {} } diff --git a/app/src/main/cpp/skyline/soc/gm20b.h b/app/src/main/cpp/skyline/soc/gm20b.h index e23d40e7..73058738 100644 --- a/app/src/main/cpp/skyline/soc/gm20b.h +++ b/app/src/main/cpp/skyline/soc/gm20b.h @@ -3,6 +3,7 @@ #pragma once +#include #include "gm20b/engines/maxwell_3d.h" #include "gm20b/gpfifo.h" #include "gm20b/gmmu.h" @@ -15,6 +16,7 @@ namespace skyline::soc::gm20b { class GM20B { public: GMMU gmmu; + gpu::interconnect::CommandExecutor executor; engine::Engine fermi2D; engine::maxwell3d::Maxwell3D maxwell3D; engine::Engine maxwellCompute; diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h index 39739736..7610ce31 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell/types.h @@ -42,7 +42,9 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { enum class ColorFormat : u32 { None = 0x0, + A2B10G10R10Unorm = 0xD1, R8G8B8A8Unorm = 0xD5, + A8B8G8R8Srgb = 0xD6, } format; struct TileMode { @@ -221,7 +223,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d::type { u8 map6 : 3; u8 map7 : 3; - size_t Map(size_t index) { + size_t operator[](size_t index) { switch (index) { case 0: return map0; diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index 949b6eb8..c6397c13 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -6,7 +6,7 @@ #include namespace skyline::soc::gm20b::engine::maxwell3d { - Maxwell3D::Maxwell3D(const DeviceState &state, GMMU &gmmu) : Engine(state), macroInterpreter(*this), context(*state.gpu, gmmu) { + Maxwell3D::Maxwell3D(const DeviceState &state, GMMU &gmmu, gpu::interconnect::CommandExecutor& executor) : Engine(state), macroInterpreter(*this), context(*state.gpu, gmmu, executor) { ResetRegs(); } @@ -245,6 +245,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { MAXWELL3D_CASE(syncpointAction, { state.logger->Debug("Increment syncpoint: {}", static_cast(syncpointAction.id)); state.soc->host1x.syncpoints.at(syncpointAction.id).Increment(); + state.soc->gm20b.executor.Execute(); }) MAXWELL3D_CASE(clearBuffers, { diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index 05a68319..d67ce560 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -4,7 +4,7 @@ #pragma once -#include +#include #include "engine.h" #include "maxwell/macro_interpreter.h" @@ -23,7 +23,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { MacroInterpreter macroInterpreter; - gpu::context::GraphicsContext context; + gpu::interconnect::GraphicsContext context; /** * @brief Writes back a semaphore result to the guest with an auto-generated timestamp (if required) @@ -241,7 +241,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { std::array macroCode{}; //!< Stores GPU macros, writes to it will wraparound on overflow - Maxwell3D(const DeviceState &state, GMMU &gmmu); + Maxwell3D(const DeviceState &state, GMMU &gmmu, gpu::interconnect::CommandExecutor& executor); /** * @brief Resets the Maxwell 3D registers to their default values