1 /* 2 * Copyright 2021 Google LLC 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "experimental/graphite/src/Gpu.h" 9 10 #include "experimental/graphite/include/BackendTexture.h" 11 #include "experimental/graphite/include/TextureInfo.h" 12 #include "experimental/graphite/src/Caps.h" 13 #include "experimental/graphite/src/CommandBuffer.h" 14 #include "experimental/graphite/src/GpuWorkSubmission.h" 15 #include "experimental/graphite/src/Log.h" 16 #include "experimental/graphite/src/ResourceProvider.h" 17 #include "src/sksl/SkSLCompiler.h" 18 19 namespace skgpu { 20 21 // This constant determines how many OutstandingSubmissions are allocated together as a block in 22 // the deque. As such it needs to balance allocating too much memory vs. incurring 23 // allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding 24 // submissions we expect to see. 25 static constexpr int kDefaultOutstandingAllocCnt = 8; 26 Gpu(sk_sp<const Caps> caps)27Gpu::Gpu(sk_sp<const Caps> caps) 28 : fOutstandingSubmissions(sizeof(OutstandingSubmission), kDefaultOutstandingAllocCnt) 29 , fCaps(std::move(caps)) { 30 // subclasses create their own subclassed resource provider 31 } 32 ~Gpu()33Gpu::~Gpu() { 34 // TODO: add disconnect? 35 36 37 // TODO: destroyResources instead? 38 // TODO: how do we handle command buffers that haven't been submitted yet? 39 this->checkForFinishedWork(SyncToCpu::kYes); 40 } 41 initCompiler()42void Gpu::initCompiler() { 43 fCompiler = std::make_unique<SkSL::Compiler>(fCaps->shaderCaps()); 44 } 45 refCaps() const46sk_sp<const Caps> Gpu::refCaps() const { 47 return fCaps; 48 } 49 submit(sk_sp<CommandBuffer> commandBuffer)50bool Gpu::submit(sk_sp<CommandBuffer> commandBuffer) { 51 if (!commandBuffer) { 52 return false; 53 } 54 55 #ifdef SK_DEBUG 56 if (!commandBuffer->hasWork()) { 57 SKGPU_LOG_W("Submitting empty command buffer!"); 58 } 59 #endif 60 61 return this->onSubmit(std::move(commandBuffer)); 62 } 63 checkForFinishedWork(SyncToCpu sync)64void Gpu::checkForFinishedWork(SyncToCpu sync) { 65 if (sync == SyncToCpu::kYes) { 66 // wait for the last submission to finish 67 OutstandingSubmission* back = (OutstandingSubmission*)fOutstandingSubmissions.back(); 68 if (back) { 69 (*back)->waitUntilFinished(this); 70 } 71 } 72 73 // Iterate over all the outstanding submissions to see if any have finished. The work 74 // submissions are in order from oldest to newest, so we start at the front to check if they 75 // have finished. If so we pop it off and move onto the next. 76 // Repeat till we find a submission that has not finished yet (and all others afterwards are 77 // also guaranteed to not have finished). 78 OutstandingSubmission* front = (OutstandingSubmission*)fOutstandingSubmissions.front(); 79 while (front && (*front)->isFinished()) { 80 // Make sure we remove before deleting as deletion might try to kick off another submit 81 // (though hopefully *not* in Graphite). 82 fOutstandingSubmissions.pop_front(); 83 // Since we used placement new we are responsible for calling the destructor manually. 84 front->~OutstandingSubmission(); 85 front = (OutstandingSubmission*)fOutstandingSubmissions.front(); 86 } 87 SkASSERT(sync == SyncToCpu::kNo || fOutstandingSubmissions.empty()); 88 } 89 createBackendTexture(SkISize dimensions,const TextureInfo & info)90BackendTexture Gpu::createBackendTexture(SkISize dimensions, const TextureInfo& info) { 91 if (dimensions.isEmpty() || dimensions.width() > this->caps()->maxTextureSize() || 92 dimensions.height() > this->caps()->maxTextureSize()) { 93 return {}; 94 } 95 96 return this->onCreateBackendTexture(dimensions, info); 97 } 98 deleteBackendTexture(BackendTexture & texture)99void Gpu::deleteBackendTexture(BackendTexture& texture) { 100 this->onDeleteBackendTexture(texture); 101 // Invalidate the texture; 102 texture = BackendTexture(); 103 } 104 105 106 } // namespace skgpu 107