/* * Copyright 2021 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "experimental/graphite/src/Gpu.h" #include "experimental/graphite/include/BackendTexture.h" #include "experimental/graphite/include/TextureInfo.h" #include "experimental/graphite/src/Caps.h" #include "experimental/graphite/src/CommandBuffer.h" #include "experimental/graphite/src/GpuWorkSubmission.h" #include "experimental/graphite/src/Log.h" #include "experimental/graphite/src/ResourceProvider.h" #include "src/sksl/SkSLCompiler.h" namespace skgpu { // This constant determines how many OutstandingSubmissions are allocated together as a block in // the deque. As such it needs to balance allocating too much memory vs. incurring // allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding // submissions we expect to see. static constexpr int kDefaultOutstandingAllocCnt = 8; Gpu::Gpu(sk_sp caps) : fOutstandingSubmissions(sizeof(OutstandingSubmission), kDefaultOutstandingAllocCnt) , fCaps(std::move(caps)) { // subclasses create their own subclassed resource provider } Gpu::~Gpu() { // TODO: add disconnect? // TODO: destroyResources instead? // TODO: how do we handle command buffers that haven't been submitted yet? this->checkForFinishedWork(SyncToCpu::kYes); } void Gpu::initCompiler() { fCompiler = std::make_unique(fCaps->shaderCaps()); } sk_sp Gpu::refCaps() const { return fCaps; } bool Gpu::submit(sk_sp commandBuffer) { if (!commandBuffer) { return false; } #ifdef SK_DEBUG if (!commandBuffer->hasWork()) { SKGPU_LOG_W("Submitting empty command buffer!"); } #endif return this->onSubmit(std::move(commandBuffer)); } void Gpu::checkForFinishedWork(SyncToCpu sync) { if (sync == SyncToCpu::kYes) { // wait for the last submission to finish OutstandingSubmission* back = (OutstandingSubmission*)fOutstandingSubmissions.back(); if (back) { (*back)->waitUntilFinished(this); } } // Iterate over all the outstanding submissions to see if any have finished. The work // submissions are in order from oldest to newest, so we start at the front to check if they // have finished. If so we pop it off and move onto the next. // Repeat till we find a submission that has not finished yet (and all others afterwards are // also guaranteed to not have finished). OutstandingSubmission* front = (OutstandingSubmission*)fOutstandingSubmissions.front(); while (front && (*front)->isFinished()) { // Make sure we remove before deleting as deletion might try to kick off another submit // (though hopefully *not* in Graphite). fOutstandingSubmissions.pop_front(); // Since we used placement new we are responsible for calling the destructor manually. front->~OutstandingSubmission(); front = (OutstandingSubmission*)fOutstandingSubmissions.front(); } SkASSERT(sync == SyncToCpu::kNo || fOutstandingSubmissions.empty()); } BackendTexture Gpu::createBackendTexture(SkISize dimensions, const TextureInfo& info) { if (dimensions.isEmpty() || dimensions.width() > this->caps()->maxTextureSize() || dimensions.height() > this->caps()->maxTextureSize()) { return {}; } return this->onCreateBackendTexture(dimensions, info); } void Gpu::deleteBackendTexture(BackendTexture& texture) { this->onDeleteBackendTexture(texture); // Invalidate the texture; texture = BackendTexture(); } } // namespace skgpu