Loading libs/renderengine/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ filegroup { "skia/Cache.cpp", "skia/ColorSpaces.cpp", "skia/GaneshVkRenderEngine.cpp", "skia/GraphiteVkRenderEngine.cpp", "skia/GLExtensions.cpp", "skia/SkiaRenderEngine.cpp", "skia/SkiaGLRenderEngine.cpp", Loading @@ -91,6 +92,8 @@ filegroup { "skia/VulkanInterface.cpp", "skia/compat/GaneshBackendTexture.cpp", "skia/compat/GaneshGpuContext.cpp", "skia/compat/GraphiteBackendTexture.cpp", "skia/compat/GraphiteGpuContext.cpp", "skia/debug/CaptureTimer.cpp", "skia/debug/CommonPool.cpp", "skia/debug/SkiaCapture.cpp", Loading libs/renderengine/skia/GraphiteVkRenderEngine.cpp 0 → 100644 +123 −0 Original line number Diff line number Diff line /* * Copyright 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "GraphiteVkRenderEngine.h" #undef LOG_TAG #define LOG_TAG "RenderEngine" #include <include/gpu/GpuTypes.h> #include <include/gpu/graphite/BackendSemaphore.h> #include <include/gpu/graphite/Context.h> #include <include/gpu/graphite/Recording.h> #include <log/log_main.h> #include <sync/sync.h> #include <memory> #include <vector> namespace android::renderengine::skia { // Graphite-specific function signature for fFinishedProc callback. static void unref_semaphore(void* semaphore, skgpu::CallbackResult result) { if (result != skgpu::CallbackResult::kSuccess) { ALOGE("Graphite submission of work to GPU failed, check for Skia errors"); } SkiaVkRenderEngine::DestroySemaphoreInfo* info = reinterpret_cast<SkiaVkRenderEngine::DestroySemaphoreInfo*>(semaphore); info->unref(); } std::unique_ptr<SkiaGpuContext> GraphiteVkRenderEngine::createContext( VulkanInterface& vulkanInterface) { return SkiaGpuContext::MakeVulkan_Graphite(vulkanInterface.getGraphiteBackendContext()); } void GraphiteVkRenderEngine::waitFence(SkiaGpuContext*, base::borrowed_fd fenceFd) { if (fenceFd.get() < 0) return; int dupedFd = dup(fenceFd.get()); if (dupedFd < 0) { ALOGE("failed to create duplicate fence fd: %d", dupedFd); sync_wait(fenceFd.get(), -1); return; } base::unique_fd fenceDup(dupedFd); VkSemaphore waitSemaphore = getVulkanInterface(isProtected()).importSemaphoreFromSyncFd(fenceDup.release()); graphite::BackendSemaphore beSemaphore(waitSemaphore); mStagedWaitSemaphores.push_back(beSemaphore); } base::unique_fd GraphiteVkRenderEngine::flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface>) { // Minimal Recording setup. Required even if there are no incoming semaphores to wait on, and if // creating the outgoing signaling semaphore fails. std::unique_ptr<graphite::Recording> recording = context->graphiteRecorder()->snap(); graphite::InsertRecordingInfo insertInfo; insertInfo.fRecording = recording.get(); VulkanInterface& vulkanInterface = getVulkanInterface(isProtected()); // This "signal" semaphore is called after rendering, but it is cleaned up in the same mechanism // as "wait" semaphores from waitFence. VkSemaphore vkSignalSemaphore = vulkanInterface.createExportableSemaphore(); graphite::BackendSemaphore backendSignalSemaphore(vkSignalSemaphore); // Collect all Vk semaphores that DestroySemaphoreInfo needs to own and delete after GPU work. std::vector<VkSemaphore> vkSemaphoresToCleanUp; if (vkSignalSemaphore != VK_NULL_HANDLE) { vkSemaphoresToCleanUp.push_back(vkSignalSemaphore); } for (auto backendWaitSemaphore : mStagedWaitSemaphores) { vkSemaphoresToCleanUp.push_back(backendWaitSemaphore.getVkSemaphore()); } DestroySemaphoreInfo* destroySemaphoreInfo = nullptr; if (vkSemaphoresToCleanUp.size() > 0) { destroySemaphoreInfo = new DestroySemaphoreInfo(vulkanInterface, std::move(vkSemaphoresToCleanUp)); insertInfo.fNumWaitSemaphores = mStagedWaitSemaphores.size(); insertInfo.fWaitSemaphores = mStagedWaitSemaphores.data(); insertInfo.fNumSignalSemaphores = 1; insertInfo.fSignalSemaphores = &backendSignalSemaphore; insertInfo.fFinishedProc = unref_semaphore; insertInfo.fFinishedContext = destroySemaphoreInfo; } const bool inserted = context->graphiteContext()->insertRecording(insertInfo); LOG_ALWAYS_FATAL_IF(!inserted, "graphite::Context::insertRecording(...) failed, check for Skia errors"); const bool submitted = context->graphiteContext()->submit(graphite::SyncToCpu::kNo); LOG_ALWAYS_FATAL_IF(!submitted, "graphite::Context::submit(...) failed, check for Skia errors"); // Skia's "backend" semaphores can be deleted immediately after inserting the recording; only // the underlying VK semaphores need to be kept until GPU work is complete. mStagedWaitSemaphores.clear(); base::unique_fd drawFenceFd(-1); if (vkSignalSemaphore != VK_NULL_HANDLE) { drawFenceFd.reset(vulkanInterface.exportSemaphoreSyncFd(vkSignalSemaphore)); } // Now that drawFenceFd has been created, we can delete RE's reference to this semaphore, as // another reference is still held until fFinishedProc is called after completion of GPU work. if (destroySemaphoreInfo) { destroySemaphoreInfo->unref(); } return drawFenceFd; } } // namespace android::renderengine::skia libs/renderengine/skia/GraphiteVkRenderEngine.h 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "SkiaVkRenderEngine.h" #include <include/gpu/graphite/BackendSemaphore.h> namespace android::renderengine::skia { class GraphiteVkRenderEngine : public SkiaVkRenderEngine { friend std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create( const RenderEngineCreationArgs& args); protected: GraphiteVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {} std::unique_ptr<SkiaGpuContext> createContext(VulkanInterface& vulkanInterface) override; void waitFence(SkiaGpuContext* context, base::borrowed_fd fenceFd) override; base::unique_fd flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface> dstSurface) override; private: std::vector<graphite::BackendSemaphore> mStagedWaitSemaphores; }; } // namespace android::renderengine::skia libs/renderengine/skia/VulkanInterface.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include "VulkanInterface.h" #include <include/gpu/GpuTypes.h> #include <include/gpu/vk/VulkanBackendContext.h> #include <log/log_main.h> #include <utils/Timers.h> Loading Loading @@ -47,6 +49,23 @@ GrVkBackendContext VulkanInterface::getGaneshBackendContext() { return backendContext; }; VulkanBackendContext VulkanInterface::getGraphiteBackendContext() { VulkanBackendContext backendContext; backendContext.fInstance = mInstance; backendContext.fPhysicalDevice = mPhysicalDevice; backendContext.fDevice = mDevice; backendContext.fQueue = mQueue; backendContext.fGraphicsQueueIndex = mQueueIndex; backendContext.fMaxAPIVersion = mApiVersion; backendContext.fVkExtensions = &mGrExtensions; backendContext.fDeviceFeatures2 = mPhysicalDeviceFeatures2; backendContext.fGetProc = mGrGetProc; backendContext.fProtectedContext = mIsProtected ? Protected::kYes : Protected::kNo; backendContext.fDeviceLostContext = this; // VulkanInterface is long-lived backendContext.fDeviceLostProc = onVkDeviceFault; return backendContext; }; VkSemaphore VulkanInterface::createExportableSemaphore() { VkExportSemaphoreCreateInfo exportInfo; exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO; Loading libs/renderengine/skia/VulkanInterface.h +5 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,10 @@ using namespace skgpu; namespace skgpu { struct VulkanBackendContext; } // namespace skgpu namespace android { namespace renderengine { namespace skia { Loading @@ -39,8 +43,8 @@ public: void init(bool protectedContent = false); void teardown(); // TODO: b/293371537 - Graphite variant (external/skia/include/gpu/vk/VulkanBackendContext.h) GrVkBackendContext getGaneshBackendContext(); VulkanBackendContext getGraphiteBackendContext(); VkSemaphore createExportableSemaphore(); VkSemaphore importSemaphoreFromSyncFd(int syncFd); int exportSemaphoreSyncFd(VkSemaphore semaphore); Loading Loading
libs/renderengine/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -84,6 +84,7 @@ filegroup { "skia/Cache.cpp", "skia/ColorSpaces.cpp", "skia/GaneshVkRenderEngine.cpp", "skia/GraphiteVkRenderEngine.cpp", "skia/GLExtensions.cpp", "skia/SkiaRenderEngine.cpp", "skia/SkiaGLRenderEngine.cpp", Loading @@ -91,6 +92,8 @@ filegroup { "skia/VulkanInterface.cpp", "skia/compat/GaneshBackendTexture.cpp", "skia/compat/GaneshGpuContext.cpp", "skia/compat/GraphiteBackendTexture.cpp", "skia/compat/GraphiteGpuContext.cpp", "skia/debug/CaptureTimer.cpp", "skia/debug/CommonPool.cpp", "skia/debug/SkiaCapture.cpp", Loading
libs/renderengine/skia/GraphiteVkRenderEngine.cpp 0 → 100644 +123 −0 Original line number Diff line number Diff line /* * Copyright 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "GraphiteVkRenderEngine.h" #undef LOG_TAG #define LOG_TAG "RenderEngine" #include <include/gpu/GpuTypes.h> #include <include/gpu/graphite/BackendSemaphore.h> #include <include/gpu/graphite/Context.h> #include <include/gpu/graphite/Recording.h> #include <log/log_main.h> #include <sync/sync.h> #include <memory> #include <vector> namespace android::renderengine::skia { // Graphite-specific function signature for fFinishedProc callback. static void unref_semaphore(void* semaphore, skgpu::CallbackResult result) { if (result != skgpu::CallbackResult::kSuccess) { ALOGE("Graphite submission of work to GPU failed, check for Skia errors"); } SkiaVkRenderEngine::DestroySemaphoreInfo* info = reinterpret_cast<SkiaVkRenderEngine::DestroySemaphoreInfo*>(semaphore); info->unref(); } std::unique_ptr<SkiaGpuContext> GraphiteVkRenderEngine::createContext( VulkanInterface& vulkanInterface) { return SkiaGpuContext::MakeVulkan_Graphite(vulkanInterface.getGraphiteBackendContext()); } void GraphiteVkRenderEngine::waitFence(SkiaGpuContext*, base::borrowed_fd fenceFd) { if (fenceFd.get() < 0) return; int dupedFd = dup(fenceFd.get()); if (dupedFd < 0) { ALOGE("failed to create duplicate fence fd: %d", dupedFd); sync_wait(fenceFd.get(), -1); return; } base::unique_fd fenceDup(dupedFd); VkSemaphore waitSemaphore = getVulkanInterface(isProtected()).importSemaphoreFromSyncFd(fenceDup.release()); graphite::BackendSemaphore beSemaphore(waitSemaphore); mStagedWaitSemaphores.push_back(beSemaphore); } base::unique_fd GraphiteVkRenderEngine::flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface>) { // Minimal Recording setup. Required even if there are no incoming semaphores to wait on, and if // creating the outgoing signaling semaphore fails. std::unique_ptr<graphite::Recording> recording = context->graphiteRecorder()->snap(); graphite::InsertRecordingInfo insertInfo; insertInfo.fRecording = recording.get(); VulkanInterface& vulkanInterface = getVulkanInterface(isProtected()); // This "signal" semaphore is called after rendering, but it is cleaned up in the same mechanism // as "wait" semaphores from waitFence. VkSemaphore vkSignalSemaphore = vulkanInterface.createExportableSemaphore(); graphite::BackendSemaphore backendSignalSemaphore(vkSignalSemaphore); // Collect all Vk semaphores that DestroySemaphoreInfo needs to own and delete after GPU work. std::vector<VkSemaphore> vkSemaphoresToCleanUp; if (vkSignalSemaphore != VK_NULL_HANDLE) { vkSemaphoresToCleanUp.push_back(vkSignalSemaphore); } for (auto backendWaitSemaphore : mStagedWaitSemaphores) { vkSemaphoresToCleanUp.push_back(backendWaitSemaphore.getVkSemaphore()); } DestroySemaphoreInfo* destroySemaphoreInfo = nullptr; if (vkSemaphoresToCleanUp.size() > 0) { destroySemaphoreInfo = new DestroySemaphoreInfo(vulkanInterface, std::move(vkSemaphoresToCleanUp)); insertInfo.fNumWaitSemaphores = mStagedWaitSemaphores.size(); insertInfo.fWaitSemaphores = mStagedWaitSemaphores.data(); insertInfo.fNumSignalSemaphores = 1; insertInfo.fSignalSemaphores = &backendSignalSemaphore; insertInfo.fFinishedProc = unref_semaphore; insertInfo.fFinishedContext = destroySemaphoreInfo; } const bool inserted = context->graphiteContext()->insertRecording(insertInfo); LOG_ALWAYS_FATAL_IF(!inserted, "graphite::Context::insertRecording(...) failed, check for Skia errors"); const bool submitted = context->graphiteContext()->submit(graphite::SyncToCpu::kNo); LOG_ALWAYS_FATAL_IF(!submitted, "graphite::Context::submit(...) failed, check for Skia errors"); // Skia's "backend" semaphores can be deleted immediately after inserting the recording; only // the underlying VK semaphores need to be kept until GPU work is complete. mStagedWaitSemaphores.clear(); base::unique_fd drawFenceFd(-1); if (vkSignalSemaphore != VK_NULL_HANDLE) { drawFenceFd.reset(vulkanInterface.exportSemaphoreSyncFd(vkSignalSemaphore)); } // Now that drawFenceFd has been created, we can delete RE's reference to this semaphore, as // another reference is still held until fFinishedProc is called after completion of GPU work. if (destroySemaphoreInfo) { destroySemaphoreInfo->unref(); } return drawFenceFd; } } // namespace android::renderengine::skia
libs/renderengine/skia/GraphiteVkRenderEngine.h 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * Copyright 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "SkiaVkRenderEngine.h" #include <include/gpu/graphite/BackendSemaphore.h> namespace android::renderengine::skia { class GraphiteVkRenderEngine : public SkiaVkRenderEngine { friend std::unique_ptr<SkiaVkRenderEngine> SkiaVkRenderEngine::create( const RenderEngineCreationArgs& args); protected: GraphiteVkRenderEngine(const RenderEngineCreationArgs& args) : SkiaVkRenderEngine(args) {} std::unique_ptr<SkiaGpuContext> createContext(VulkanInterface& vulkanInterface) override; void waitFence(SkiaGpuContext* context, base::borrowed_fd fenceFd) override; base::unique_fd flushAndSubmit(SkiaGpuContext* context, sk_sp<SkSurface> dstSurface) override; private: std::vector<graphite::BackendSemaphore> mStagedWaitSemaphores; }; } // namespace android::renderengine::skia
libs/renderengine/skia/VulkanInterface.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,8 @@ #include "VulkanInterface.h" #include <include/gpu/GpuTypes.h> #include <include/gpu/vk/VulkanBackendContext.h> #include <log/log_main.h> #include <utils/Timers.h> Loading Loading @@ -47,6 +49,23 @@ GrVkBackendContext VulkanInterface::getGaneshBackendContext() { return backendContext; }; VulkanBackendContext VulkanInterface::getGraphiteBackendContext() { VulkanBackendContext backendContext; backendContext.fInstance = mInstance; backendContext.fPhysicalDevice = mPhysicalDevice; backendContext.fDevice = mDevice; backendContext.fQueue = mQueue; backendContext.fGraphicsQueueIndex = mQueueIndex; backendContext.fMaxAPIVersion = mApiVersion; backendContext.fVkExtensions = &mGrExtensions; backendContext.fDeviceFeatures2 = mPhysicalDeviceFeatures2; backendContext.fGetProc = mGrGetProc; backendContext.fProtectedContext = mIsProtected ? Protected::kYes : Protected::kNo; backendContext.fDeviceLostContext = this; // VulkanInterface is long-lived backendContext.fDeviceLostProc = onVkDeviceFault; return backendContext; }; VkSemaphore VulkanInterface::createExportableSemaphore() { VkExportSemaphoreCreateInfo exportInfo; exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO; Loading
libs/renderengine/skia/VulkanInterface.h +5 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,10 @@ using namespace skgpu; namespace skgpu { struct VulkanBackendContext; } // namespace skgpu namespace android { namespace renderengine { namespace skia { Loading @@ -39,8 +43,8 @@ public: void init(bool protectedContent = false); void teardown(); // TODO: b/293371537 - Graphite variant (external/skia/include/gpu/vk/VulkanBackendContext.h) GrVkBackendContext getGaneshBackendContext(); VulkanBackendContext getGraphiteBackendContext(); VkSemaphore createExportableSemaphore(); VkSemaphore importSemaphoreFromSyncFd(int syncFd); int exportSemaphoreSyncFd(VkSemaphore semaphore); Loading