blob: 81d9ebb5be82740128fe9c263cd6f229dd3ff11e [file] [log] [blame]
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001/*
Jim Van Verth03b8ab22020-02-24 11:36:15 -05002 * Copyright 2020 Google LLC
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05008#include "src/gpu/d3d/GrD3DGpu.h"
9
Jim Van Verth96bfeff2020-04-09 14:36:12 -040010#include "include/gpu/GrBackendSurface.h"
Jim Van Verth9aa9a682020-04-01 10:13:48 -040011#include "include/gpu/d3d/GrD3DBackendContext.h"
Jim Van Verthc632aa62020-04-17 16:58:20 -040012#include "src/core/SkConvertPixels.h"
Mike Reed13711eb2020-07-14 17:16:32 -040013#include "src/core/SkMipmap.h"
Jim Van Verth43a6e172020-06-23 11:59:08 -040014#include "src/gpu/GrBackendUtils.h"
Jim Van Verthc632aa62020-04-17 16:58:20 -040015#include "src/gpu/GrDataUtils.h"
Brian Salomon4cfae3b2020-07-23 10:33:24 -040016#include "src/gpu/GrTexture.h"
Robert Phillipsae67c522021-03-03 11:03:38 -050017#include "src/gpu/GrThreadSafePipelineBuilder.h"
Jim Van Verth1b89eb72020-09-23 16:29:51 -040018#include "src/gpu/d3d/GrD3DAMDMemoryAllocator.h"
Greg Danielc0d69152020-10-08 14:59:00 -040019#include "src/gpu/d3d/GrD3DAttachment.h"
Jim Van Verthd6ad4802020-04-03 14:59:20 -040020#include "src/gpu/d3d/GrD3DBuffer.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050021#include "src/gpu/d3d/GrD3DCaps.h"
22#include "src/gpu/d3d/GrD3DOpsRenderPass.h"
Jim Van Verthc1a67b52020-06-25 13:10:29 -040023#include "src/gpu/d3d/GrD3DSemaphore.h"
Jim Van Verthaa90dad2020-03-30 15:00:39 -040024#include "src/gpu/d3d/GrD3DTexture.h"
25#include "src/gpu/d3d/GrD3DTextureRenderTarget.h"
26#include "src/gpu/d3d/GrD3DUtil.h"
Greg Daniel5fc5c812020-04-23 10:30:23 -040027#include "src/sksl/SkSLCompiler.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050028
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040029#if GR_TEST_UTILS
30#include <DXProgrammableCapture.h>
31#endif
32
Robert Phillipsae67c522021-03-03 11:03:38 -050033GrThreadSafePipelineBuilder* GrD3DGpu::pipelineBuilder() {
34 return nullptr;
35}
36
37sk_sp<GrThreadSafePipelineBuilder> GrD3DGpu::refPipelineBuilder() {
38 return nullptr;
39}
40
41
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050042sk_sp<GrGpu> GrD3DGpu::Make(const GrD3DBackendContext& backendContext,
Adlai Holler3d0359a2020-07-09 15:35:55 -040043 const GrContextOptions& contextOptions, GrDirectContext* direct) {
Jim Van Verth1b89eb72020-09-23 16:29:51 -040044 sk_sp<GrD3DMemoryAllocator> memoryAllocator = backendContext.fMemoryAllocator;
45 if (!memoryAllocator) {
46 // We were not given a memory allocator at creation
47 memoryAllocator = GrD3DAMDMemoryAllocator::Make(
48 backendContext.fAdapter.get(), backendContext.fDevice.get());
49 }
50 if (!memoryAllocator) {
51 SkDEBUGFAIL("No supplied Direct3D memory allocator and unable to create one internally.");
52 return nullptr;
53 }
54
55 return sk_sp<GrGpu>(new GrD3DGpu(direct, contextOptions, backendContext, memoryAllocator));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050056}
57
Greg Daniel83ed2132020-03-24 13:15:33 -040058// This constant determines how many OutstandingCommandLists are allocated together as a block in
59// the deque. As such it needs to balance allocating too much memory vs. incurring
60// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
61// command lists we expect to see.
62static const int kDefaultOutstandingAllocCnt = 8;
63
Jim Van Verth711b0392020-07-23 16:45:00 -040064// constants have to be aligned to 256
65constexpr int kConstantAlignment = 256;
66
Adlai Holler3d0359a2020-07-09 15:35:55 -040067GrD3DGpu::GrD3DGpu(GrDirectContext* direct, const GrContextOptions& contextOptions,
Jim Van Verth1b89eb72020-09-23 16:29:51 -040068 const GrD3DBackendContext& backendContext,
69 sk_sp<GrD3DMemoryAllocator> allocator)
Adlai Holler3d0359a2020-07-09 15:35:55 -040070 : INHERITED(direct)
Jim Van Verth03b8ab22020-02-24 11:36:15 -050071 , fDevice(backendContext.fDevice)
Greg Daniel02c45902020-03-09 10:58:09 -040072 , fQueue(backendContext.fQueue)
Jim Van Verth1b89eb72020-09-23 16:29:51 -040073 , fMemoryAllocator(std::move(allocator))
Greg Daniel83ed2132020-03-24 13:15:33 -040074 , fResourceProvider(this)
Greg Danielcffb0622020-07-16 13:19:17 -040075 , fStagingBufferManager(this)
Jim Van Verth711b0392020-07-23 16:45:00 -040076 , fConstantsRingBuffer(this, 128 * 1024, kConstantAlignment, GrGpuBufferType::kVertex)
Brian Osmand7e76592020-11-02 12:26:22 -050077 , fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt) {
Brian Osmancbdc2612020-11-23 15:30:48 -050078 this->initCapsAndCompiler(sk_make_sp<GrD3DCaps>(contextOptions,
79 backendContext.fAdapter.get(),
80 backendContext.fDevice.get()));
Greg Daniel85da3362020-03-09 15:18:35 -040081
82 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
Greg Daniele52c9782020-03-23 14:18:37 -040083 SkASSERT(fCurrentDirectCommandList);
Greg Daniel83ed2132020-03-24 13:15:33 -040084
85 SkASSERT(fCurrentFenceValue == 0);
Jim Van Verthe3810362020-07-01 10:12:11 -040086 GR_D3D_CALL_ERRCHECK(fDevice->CreateFence(fCurrentFenceValue, D3D12_FENCE_FLAG_NONE,
87 IID_PPV_ARGS(&fFence)));
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040088
89#if GR_TEST_UTILS
90 HRESULT getAnalysis = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&fGraphicsAnalysis));
91 if (FAILED(getAnalysis)) {
92 fGraphicsAnalysis = nullptr;
93 }
94#endif
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050095}
96
Greg Daniel83ed2132020-03-24 13:15:33 -040097GrD3DGpu::~GrD3DGpu() {
98 this->destroyResources();
99}
100
101void GrD3DGpu::destroyResources() {
102 if (fCurrentDirectCommandList) {
103 fCurrentDirectCommandList->close();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400104 fCurrentDirectCommandList->reset();
Greg Daniel83ed2132020-03-24 13:15:33 -0400105 }
106
107 // We need to make sure everything has finished on the queue.
Jim Van Verth3b0d7d12020-07-06 11:52:42 -0400108 this->waitForQueueCompletion();
Greg Daniel83ed2132020-03-24 13:15:33 -0400109
110 SkDEBUGCODE(uint64_t fenceValue = fFence->GetCompletedValue();)
111
112 // We used a placement new for each object in fOutstandingCommandLists, so we're responsible
113 // for calling the destructor on each of them as well.
114 while (!fOutstandingCommandLists.empty()) {
Jim Van Verthf43da142020-06-09 16:34:43 -0400115 OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel83ed2132020-03-24 13:15:33 -0400116 SkASSERT(list->fFenceValue <= fenceValue);
117 // No reason to recycle the command lists since we are destroying all resources anyways.
118 list->~OutstandingCommandList();
Jim Van Verthf43da142020-06-09 16:34:43 -0400119 fOutstandingCommandLists.pop_front();
Greg Daniel83ed2132020-03-24 13:15:33 -0400120 }
Jim Van Verthf2788862020-06-03 17:33:12 -0400121
Greg Danielcffb0622020-07-16 13:19:17 -0400122 fStagingBufferManager.reset();
123
Jim Van Verthf2788862020-06-03 17:33:12 -0400124 fResourceProvider.destroyResources();
Greg Daniel83ed2132020-03-24 13:15:33 -0400125}
Greg Daniel31a7b072020-02-26 15:31:49 -0500126
Greg Daniel65476e02020-10-27 09:20:20 -0400127GrOpsRenderPass* GrD3DGpu::onGetOpsRenderPass(
Greg Danielc0d69152020-10-08 14:59:00 -0400128 GrRenderTarget* rt,
129 GrAttachment*,
130 GrSurfaceOrigin origin,
131 const SkIRect& bounds,
Greg Daniel9a18b082020-08-14 14:03:50 -0400132 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
133 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
134 const SkTArray<GrSurfaceProxy*, true>& sampledProxies,
Greg Daniel21774362020-09-14 10:36:43 -0400135 GrXferBarrierFlags renderPassXferBarriers) {
Greg Daniel31a7b072020-02-26 15:31:49 -0500136 if (!fCachedOpsRenderPass) {
137 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
138 }
139
140 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
141 return nullptr;
142 }
143 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500144}
145
Jim Van Verthc632aa62020-04-17 16:58:20 -0400146bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
Greg Daniel83ed2132020-03-24 13:15:33 -0400147 SkASSERT(fCurrentDirectCommandList);
148
Jim Van Verth3eadce22020-06-01 11:34:49 -0400149 fResourceProvider.prepForSubmit();
150
Jim Van Verth5fba9ae2020-09-21 17:18:04 -0400151 GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
Jim Van Verthc632aa62020-04-17 16:58:20 -0400152 if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
153 return false;
154 } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
155 if (sync == SyncQueue::kForce) {
Jim Van Verth3b0d7d12020-07-06 11:52:42 -0400156 this->waitForQueueCompletion();
Jim Van Verth682a2f42020-05-13 16:54:09 -0400157 this->checkForFinishedCommandLists();
Jim Van Verthc632aa62020-04-17 16:58:20 -0400158 }
159 return true;
160 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400161
Greg Daniela581a8b2020-06-19 15:22:18 -0400162 // We just submitted the command list so make sure all GrD3DPipelineState's mark their cached
163 // uniform data as dirty.
164 fResourceProvider.markPipelineStateUniformsDirty();
165
Jim Van Verth1e6460d2020-06-30 15:47:52 -0400166 GrFence fence = this->insertFence();
Greg Daniel83ed2132020-03-24 13:15:33 -0400167 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
Jim Van Verth1e6460d2020-06-30 15:47:52 -0400168 std::move(fCurrentDirectCommandList), fence);
Greg Daniel83ed2132020-03-24 13:15:33 -0400169
Jim Van Verthc632aa62020-04-17 16:58:20 -0400170 if (sync == SyncQueue::kForce) {
Jim Van Verth3b0d7d12020-07-06 11:52:42 -0400171 this->waitForQueueCompletion();
Jim Van Verthc632aa62020-04-17 16:58:20 -0400172 }
173
Greg Daniel83ed2132020-03-24 13:15:33 -0400174 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
175
176 // This should be done after we have a new command list in case the freeing of any resources
177 // held by a finished command list causes us send a new command to the gpu (like changing the
178 // resource state.
179 this->checkForFinishedCommandLists();
180
181 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400182 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400183}
184
185void GrD3DGpu::checkForFinishedCommandLists() {
186 uint64_t currentFenceValue = fFence->GetCompletedValue();
187
188 // Iterate over all the outstanding command lists to see if any have finished. The commands
189 // lists are in order from oldest to newest, so we start at the front to check if their fence
190 // value is less than the last signaled value. If so we pop it off and move onto the next.
191 // Repeat till we find a command list that has not finished yet (and all others afterwards are
192 // also guaranteed to not have finished).
Jim Van Verthdd3b4012020-06-30 15:28:17 -0400193 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
194 while (front && front->fFenceValue <= currentFenceValue) {
195 std::unique_ptr<GrD3DDirectCommandList> currList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400196 // Since we used placement new we are responsible for calling the destructor manually.
197 front->~OutstandingCommandList();
198 fOutstandingCommandLists.pop_front();
Jim Van Verthdd3b4012020-06-30 15:28:17 -0400199 fResourceProvider.recycleDirectCommandList(std::move(currList));
200 front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel83ed2132020-03-24 13:15:33 -0400201 }
202}
203
Jim Van Verth3b0d7d12020-07-06 11:52:42 -0400204void GrD3DGpu::waitForQueueCompletion() {
205 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
206 HANDLE fenceEvent;
207 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
208 SkASSERT(fenceEvent);
209 GR_D3D_CALL_ERRCHECK(fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent));
210 WaitForSingleObject(fenceEvent, INFINITE);
211 CloseHandle(fenceEvent);
212 }
213}
214
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500215void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400216 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
217
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500218 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400219 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500220}
221
Greg Danield4928d02020-06-19 11:13:26 -0400222void GrD3DGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
223 GrGpuFinishedContext finishedContext) {
224 SkASSERT(finishedProc);
Brian Salomon694ff172020-11-04 16:54:28 -0500225 this->addFinishedCallback(GrRefCntedCallback::Make(finishedProc, finishedContext));
Jim Van Verth43a6e172020-06-23 11:59:08 -0400226}
227
228void GrD3DGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) {
229 SkASSERT(finishedCallback);
Greg Danield4928d02020-06-19 11:13:26 -0400230 // Besides the current command list, we also add the finishedCallback to the newest outstanding
231 // command list. Our contract for calling the proc is that all previous submitted command lists
232 // have finished when we call it. However, if our current command list has no work when it is
233 // flushed it will drop its ref to the callback immediately. But the previous work may not have
234 // finished. It is safe to only add the proc to the newest outstanding commandlist cause that
235 // must finish after all previously submitted command lists.
236 OutstandingCommandList* back = (OutstandingCommandList*)fOutstandingCommandLists.back();
237 if (back) {
238 back->fCommandList->addFinishedCallback(finishedCallback);
239 }
240 fCurrentDirectCommandList->addFinishedCallback(std::move(finishedCallback));
241}
242
Jim Van Verth765c5922020-08-10 17:23:50 -0400243void GrD3DGpu::querySampleLocations(GrRenderTarget* renderTarget,
244 SkTArray<SkPoint>* sampleLocations) {
245 // By default, the Direct3D backend uses the standard sample locations defined by the docs.
246 // These are transformed from D3D's integer coordinate system with origin at the center,
247 // to our normalized coordinate system with origin at the upper left.
248 // This ends up corresponding with Vulkan's sample locations.
249 SkASSERT(this->caps()->sampleLocationsSupport());
250 static constexpr SkPoint kStandardSampleLocations_1[1] = {
251 {0.5f, 0.5f} };
252 static constexpr SkPoint kStandardSampleLocations_2[2] = {
253 {0.75f, 0.75f}, {0.25f, 0.25f} };
254 static constexpr SkPoint kStandardSampleLocations_4[4] = {
255 {0.375f, 0.125f}, {0.875f, 0.375f}, {0.125f, 0.625f}, {0.625f, 0.875f} };
256 static constexpr SkPoint kStandardSampleLocations_8[8] = {
257 {0.5625f, 0.3125f}, {0.4375f, 0.6875f}, {0.8125f, 0.5625f}, {0.3125f, 0.1875f},
258 {0.1875f, 0.8125f}, {0.0625f, 0.4375f}, {0.6875f, 0.9375f}, {0.9375f, 0.0625f} };
259 static constexpr SkPoint kStandardSampleLocations_16[16] = {
260 {0.5625f, 0.5625f}, {0.4375f, 0.3125f}, {0.3125f, 0.625f}, {0.75f, 0.4375f},
261 {0.1875f, 0.375f}, {0.625f, 0.8125f}, {0.8125f, 0.6875f}, {0.6875f, 0.1875f},
262 {0.375f, 0.875f}, {0.5f, 0.0625f}, {0.25f, 0.125f}, {0.125f, 0.75f},
263 {0.0f, 0.5f}, {0.9375f, 0.25f}, {0.875f, 0.9375f}, {0.0625f, 0.0f} };
264
265 int numSamples = renderTarget->numSamples();
266 // TODO: support mixed samples?
267 SkASSERT(numSamples > 1);
268 SkASSERT(!renderTarget->getStencilAttachment() ||
269 numSamples == renderTarget->getStencilAttachment()->numSamples());
270
271 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(renderTarget);
272 unsigned int pattern = d3dRT->msaaTextureResource()->sampleQualityPattern();
273 if (pattern == DXGI_CENTER_MULTISAMPLE_QUALITY_PATTERN) {
274 sampleLocations->push_back_n(numSamples, kStandardSampleLocations_1[0]);
275 return;
276 }
277 SkASSERT(pattern == DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN);
278
279 switch (numSamples) {
280 case 2:
281 sampleLocations->push_back_n(2, kStandardSampleLocations_2);
282 break;
283 case 4:
284 sampleLocations->push_back_n(4, kStandardSampleLocations_4);
285 break;
286 case 8:
287 sampleLocations->push_back_n(8, kStandardSampleLocations_8);
288 break;
289 case 16:
290 sampleLocations->push_back_n(16, kStandardSampleLocations_16);
291 break;
292 default:
293 SK_ABORT("Invalid sample count.");
294 break;
295 }
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500296}
297
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400298sk_sp<GrD3DTexture> GrD3DGpu::createD3DTexture(SkISize dimensions,
299 DXGI_FORMAT dxgiFormat,
300 GrRenderable renderable,
301 int renderTargetSampleCnt,
302 SkBudgeted budgeted,
303 GrProtected isProtected,
304 int mipLevelCount,
Brian Salomona6db5102020-07-21 09:56:23 -0400305 GrMipmapStatus mipmapStatus) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400306 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400307 if (renderable == GrRenderable::kYes) {
308 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
309 }
310
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400311 // This desc refers to a texture that will be read by the client. Thus even if msaa is
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400312 // requested, this describes the resolved texture. Therefore we always have samples set
313 // to 1.
314 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400315 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400316 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
317 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
318 // might want to manually set alignment to 4KB for smaller textures
319 resourceDesc.Alignment = 0;
320 resourceDesc.Width = dimensions.fWidth;
321 resourceDesc.Height = dimensions.fHeight;
322 resourceDesc.DepthOrArraySize = 1;
323 resourceDesc.MipLevels = mipLevelCount;
324 resourceDesc.Format = dxgiFormat;
325 resourceDesc.SampleDesc.Count = 1;
Jim Van Verth765c5922020-08-10 17:23:50 -0400326 resourceDesc.SampleDesc.Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400327 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400328 resourceDesc.Flags = usageFlags;
329
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400330 if (renderable == GrRenderable::kYes) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400331 return GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400332 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
Brian Salomona6db5102020-07-21 09:56:23 -0400333 mipmapStatus);
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400334 } else {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400335 return GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
Brian Salomona6db5102020-07-21 09:56:23 -0400336 mipmapStatus);
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400337 }
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400338}
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400339
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400340sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
341 const GrBackendFormat& format,
342 GrRenderable renderable,
343 int renderTargetSampleCnt,
344 SkBudgeted budgeted,
345 GrProtected isProtected,
346 int mipLevelCount,
347 uint32_t levelClearMask) {
348 DXGI_FORMAT dxgiFormat;
349 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
350 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
351
Brian Salomona6db5102020-07-21 09:56:23 -0400352 GrMipmapStatus mipmapStatus = mipLevelCount > 1 ? GrMipmapStatus::kDirty
353 : GrMipmapStatus::kNotAllocated;
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400354
355 sk_sp<GrD3DTexture> tex = this->createD3DTexture(dimensions, dxgiFormat, renderable,
356 renderTargetSampleCnt, budgeted, isProtected,
Brian Salomona6db5102020-07-21 09:56:23 -0400357 mipLevelCount, mipmapStatus);
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400358 if (!tex) {
359 return nullptr;
360 }
361
362 if (levelClearMask) {
363 // TODO
364 }
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400365
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400366 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500367}
368
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400369static void copy_compressed_data(char* mapPtr, DXGI_FORMAT dxgiFormat,
370 D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
371 UINT* numRows, UINT64* rowSizeInBytes,
372 const void* compressedData, int numMipLevels) {
373 SkASSERT(compressedData && numMipLevels);
374 SkASSERT(GrDxgiFormatIsCompressed(dxgiFormat));
375 SkASSERT(mapPtr);
376
377 const char* src = static_cast<const char*>(compressedData);
378 for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
379 // copy data into the buffer, skipping any trailing bytes
380 char* dst = mapPtr + placedFootprints[currentMipLevel].Offset;
381 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
382 src, rowSizeInBytes[currentMipLevel], rowSizeInBytes[currentMipLevel],
383 numRows[currentMipLevel]);
384 src += numRows[currentMipLevel] * rowSizeInBytes[currentMipLevel];
385 }
386}
387
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500388sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
389 const GrBackendFormat& format,
390 SkBudgeted budgeted,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400391 GrMipmapped mipMapped,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500392 GrProtected isProtected,
393 const void* data, size_t dataSize) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400394 DXGI_FORMAT dxgiFormat;
395 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
396 SkASSERT(GrDxgiFormatIsCompressed(dxgiFormat));
397
398 SkDEBUGCODE(SkImage::CompressionType compression = GrBackendFormatToCompressionType(format));
399 SkASSERT(dataSize == SkCompressedFormatDataSize(compression, dimensions,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400400 mipMapped == GrMipmapped::kYes));
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400401
402 int mipLevelCount = 1;
Brian Salomon7e67dca2020-07-21 09:27:25 -0400403 if (mipMapped == GrMipmapped::kYes) {
Mike Reed13711eb2020-07-14 17:16:32 -0400404 mipLevelCount = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400405 }
Brian Salomona6db5102020-07-21 09:56:23 -0400406 GrMipmapStatus mipmapStatus = mipLevelCount > 1 ? GrMipmapStatus::kValid
407 : GrMipmapStatus::kNotAllocated;
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400408
409 sk_sp<GrD3DTexture> d3dTex = this->createD3DTexture(dimensions, dxgiFormat, GrRenderable::kNo,
410 1, budgeted, isProtected,
Brian Salomona6db5102020-07-21 09:56:23 -0400411 mipLevelCount, mipmapStatus);
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400412 if (!d3dTex) {
413 return nullptr;
414 }
415
416 ID3D12Resource* d3dResource = d3dTex->d3dResource();
417 SkASSERT(d3dResource);
418 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
419 // Either upload only the first miplevel or all miplevels
420 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
421
422 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
423 SkAutoTMalloc<UINT> numRows(mipLevelCount);
424 SkAutoTMalloc<UINT64> rowSizeInBytes(mipLevelCount);
425 UINT64 combinedBufferSize;
426 // We reset the width and height in the description to match our subrectangle size
427 // so we don't end up allocating more space than we need.
428 desc.Width = dimensions.width();
429 desc.Height = dimensions.height();
430 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
431 numRows.get(), rowSizeInBytes.get(), &combinedBufferSize);
432 SkASSERT(combinedBufferSize);
433
Greg Danielcffb0622020-07-16 13:19:17 -0400434 GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
435 combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
436 if (!slice.fBuffer) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400437 return false;
438 }
Greg Danielcffb0622020-07-16 13:19:17 -0400439
440 char* bufferData = (char*)slice.fOffsetMapPtr;
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400441
442 copy_compressed_data(bufferData, desc.Format, placedFootprints.get(), numRows.get(),
443 rowSizeInBytes.get(), data, mipLevelCount);
444
Greg Danielcffb0622020-07-16 13:19:17 -0400445 // Update the offsets in the footprints to be relative to the slice's offset
446 for (int i = 0; i < mipLevelCount; ++i) {
447 placedFootprints[i].Offset += slice.fOffset;
448 }
449
Greg Daniel69267912020-07-24 10:42:53 -0400450 ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer)->d3dResource();
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400451 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, d3dTex.get(), mipLevelCount,
452 placedFootprints.get(), 0, 0);
453
454 return std::move(d3dTex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500455}
456
Jim Van Verth9145f782020-04-28 12:01:12 -0400457static int get_surface_sample_cnt(GrSurface* surf) {
458 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
459 return rt->numSamples();
460 }
461 return 0;
462}
463
464bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
465 const SkIPoint& dstPoint) {
466
467 if (src->isProtected() && !dst->isProtected()) {
468 SkDebugf("Can't copy from protected memory to non-protected");
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400469 return false;
470 }
Jim Van Verth9145f782020-04-28 12:01:12 -0400471
472 int dstSampleCnt = get_surface_sample_cnt(dst);
473 int srcSampleCnt = get_surface_sample_cnt(src);
474
475 GrD3DTextureResource* dstTexResource;
476 GrD3DTextureResource* srcTexResource;
477 GrRenderTarget* dstRT = dst->asRenderTarget();
478 if (dstRT) {
479 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
480 dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
481 } else {
482 SkASSERT(dst->asTexture());
483 dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
484 }
485 GrRenderTarget* srcRT = src->asRenderTarget();
486 if (srcRT) {
487 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
488 srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
489 } else {
490 SkASSERT(src->asTexture());
491 srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
492 }
493
494 DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
495 DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
496
497 if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
498 this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
499 return true;
500 }
501
502 if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
503 this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
504 return true;
505 }
506
507 return false;
508}
509
510void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
511 GrD3DTextureResource* dstResource,
512 GrD3DTextureResource* srcResource,
513 const SkIRect& srcRect, const SkIPoint& dstPoint) {
514#ifdef SK_DEBUG
515 int dstSampleCnt = get_surface_sample_cnt(dst);
516 int srcSampleCnt = get_surface_sample_cnt(src);
517 DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
518 DXGI_FORMAT srcFormat;
519 SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
520 SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
521#endif
522 if (src->isProtected() && !dst->isProtected()) {
523 SkDebugf("Can't copy from protected memory to non-protected");
524 return;
525 }
526
527 dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
528 srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
529
530 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
531 dstLocation.pResource = dstResource->d3dResource();
532 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
533 dstLocation.SubresourceIndex = 0;
534
535 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
536 srcLocation.pResource = srcResource->d3dResource();
537 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
538 srcLocation.SubresourceIndex = 0;
539
540 D3D12_BOX srcBox = {};
541 srcBox.left = srcRect.fLeft;
542 srcBox.top = srcRect.fTop;
543 srcBox.right = srcRect.fRight;
544 srcBox.bottom = srcRect.fBottom;
545 srcBox.front = 0;
546 srcBox.back = 1;
547 // TODO: use copyResource if copying full resource and sizes match
Greg Daniel69267912020-07-24 10:42:53 -0400548 fCurrentDirectCommandList->copyTextureRegionToTexture(dstResource->resource(),
549 &dstLocation,
550 dstPoint.fX, dstPoint.fY,
551 srcResource->resource(),
552 &srcLocation,
553 &srcBox);
Jim Van Verth9145f782020-04-28 12:01:12 -0400554
555 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
556 srcRect.width(), srcRect.height());
557 // The rect is already in device space so we pass in kTopLeft so no flip is done.
558 this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
559}
560
561void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
562 const SkIPoint& dstPoint) {
Jim Van Verth275f4192020-07-07 15:36:41 -0400563 GrD3DRenderTarget* srcRT = static_cast<GrD3DRenderTarget*>(src->asRenderTarget());
564 SkASSERT(srcRT);
565
566 this->resolveTexture(dst, dstPoint.fX, dstPoint.fY, srcRT, srcRect);
567}
568
569void GrD3DGpu::resolveTexture(GrSurface* dst, int32_t dstX, int32_t dstY,
570 GrD3DRenderTarget* src, const SkIRect& srcIRect) {
571 SkASSERT(dst);
572 SkASSERT(src && src->numSamples() > 1 && src->msaaTextureResource());
573
574 D3D12_RECT srcRect = { srcIRect.fLeft, srcIRect.fTop, srcIRect.fRight, srcIRect.fBottom };
575
576 GrD3DTextureResource* dstTextureResource;
577 GrRenderTarget* dstRT = dst->asRenderTarget();
578 if (dstRT) {
579 dstTextureResource = static_cast<GrD3DRenderTarget*>(dstRT);
580 } else {
581 SkASSERT(dst->asTexture());
582 dstTextureResource = static_cast<GrD3DTexture*>(dst->asTexture());
583 }
584
585 dstTextureResource->setResourceState(this, D3D12_RESOURCE_STATE_RESOLVE_DEST);
586 src->msaaTextureResource()->setResourceState(this, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
587
588 fCurrentDirectCommandList->resolveSubresourceRegion(dstTextureResource, dstX, dstY,
589 src->msaaTextureResource(), &srcRect);
590}
591
Jim Van Verthbb61fe32020-07-07 16:39:04 -0400592void GrD3DGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect) {
Jim Van Verth275f4192020-07-07 15:36:41 -0400593 SkASSERT(target->numSamples() > 1);
594 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(target);
Brian Salomon72c7b982020-10-06 10:07:38 -0400595 SkASSERT(rt->msaaTextureResource() && rt != rt->msaaTextureResource());
Jim Van Verth275f4192020-07-07 15:36:41 -0400596
597 this->resolveTexture(target, resolveRect.fLeft, resolveRect.fTop, rt, resolveRect);
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400598}
599
Jim Van Verthba7f2292020-04-21 08:56:47 -0400600bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
601 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
602 size_t rowBytes) {
603 SkASSERT(surface);
604
605 if (surfaceColorType != dstColorType) {
606 return false;
607 }
608
609 // Set up src location and box
Jim Van Verthc12aad92020-04-24 16:19:01 -0400610 GrD3DTextureResource* texResource = nullptr;
611 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
612 if (rt) {
613 texResource = rt;
614 } else {
615 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
616 }
617
618 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400619 return false;
620 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400621
Jim Van Verthba7f2292020-04-21 08:56:47 -0400622 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400623 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400624 SkASSERT(srcLocation.pResource);
625 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
626 srcLocation.SubresourceIndex = 0;
627
628 D3D12_BOX srcBox = {};
629 srcBox.left = left;
630 srcBox.top = top;
631 srcBox.right = left + width;
632 srcBox.bottom = top + height;
633 srcBox.front = 0;
634 srcBox.back = 1;
635
636 // Set up dst location and create transfer buffer
637 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
638 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400639 UINT64 transferTotalBytes;
640 const UINT64 baseOffset = 0;
641 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
642 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400643 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400644 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400645 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Greg Daniel0eca74c2020-10-01 13:46:00 -0400646 if (GrDxgiFormatBytesPerBlock(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400647 return false;
648 }
649 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400650
651 // TODO: implement some way of reusing buffers instead of making a new one every time.
652 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
653 GrGpuBufferType::kXferGpuToCpu,
654 kDynamic_GrAccessPattern);
655 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
656 dstLocation.pResource = d3dBuf->d3dResource();
657
658 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400659 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400660
Greg Daniel69267912020-07-24 10:42:53 -0400661 fCurrentDirectCommandList->copyTextureRegionToBuffer(transferBuffer, &dstLocation, 0, 0,
662 texResource->resource(), &srcLocation,
663 &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400664 this->submitDirectCommandList(SyncQueue::kForce);
665
666 const void* mappedMemory = transferBuffer->map();
667
668 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400669 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400670
671 transferBuffer->unmap();
672
673 return true;
674}
675
676bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
677 GrColorType surfaceColorType, GrColorType srcColorType,
678 const GrMipLevel texels[], int mipLevelCount,
679 bool prepForTexSampling) {
680 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
681 if (!d3dTex) {
682 return false;
683 }
684
685 // Make sure we have at least the base level
686 if (!mipLevelCount || !texels[0].fPixels) {
687 return false;
688 }
689
690 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
691 bool success = false;
692
693 // Need to change the resource state to COPY_DEST in order to upload to it
694 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
695
Brian Salomon4cfae3b2020-07-23 10:33:24 -0400696 SkASSERT(mipLevelCount <= d3dTex->maxMipmapLevel() + 1);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400697 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
698 mipLevelCount);
699
700 if (prepForTexSampling) {
701 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
702 }
703
704 return success;
705}
706
707bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
708 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
709 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
710 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
711 SkASSERT(1 == mipLevelCount ||
712 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
713
714 // We assume that if the texture has mip levels, we either upload to all the levels or just the
715 // first.
Brian Salomon4cfae3b2020-07-23 10:33:24 -0400716 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->maxMipmapLevel() + 1));
Jim Van Verthba7f2292020-04-21 08:56:47 -0400717
718 if (width == 0 || height == 0) {
719 return false;
720 }
721
722 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
723 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
724
725 ID3D12Resource* d3dResource = tex->d3dResource();
726 SkASSERT(d3dResource);
727 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
728 // Either upload only the first miplevel or all miplevels
729 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
730
731 if (1 == mipLevelCount && !texels[0].fPixels) {
732 return true; // no data to upload
733 }
734
735 for (int i = 0; i < mipLevelCount; ++i) {
736 // We do not allow any gaps in the mip data
737 if (!texels[i].fPixels) {
738 return false;
739 }
740 }
741
742 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400743 UINT64 combinedBufferSize;
744 // We reset the width and height in the description to match our subrectangle size
745 // so we don't end up allocating more space than we need.
746 desc.Width = width;
747 desc.Height = height;
748 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400749 nullptr, nullptr, &combinedBufferSize);
750 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400751 SkASSERT(combinedBufferSize);
752
Greg Danielcffb0622020-07-16 13:19:17 -0400753 GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
754 combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
755 if (!slice.fBuffer) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400756 return false;
757 }
Greg Danielcffb0622020-07-16 13:19:17 -0400758
759 char* bufferData = (char*)slice.fOffsetMapPtr;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400760
761 int currentWidth = width;
762 int currentHeight = height;
763 int layerHeight = tex->height();
764
765 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
766 if (texels[currentMipLevel].fPixels) {
767 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
768
Jim Van Verthfdd36852020-04-21 16:29:44 -0400769 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400770 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
771
772 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
773
774 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400775 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400776 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
777 src, srcRowBytes, trimRowBytes, currentHeight);
778 }
779 currentWidth = std::max(1, currentWidth / 2);
780 currentHeight = std::max(1, currentHeight / 2);
781 layerHeight = currentHeight;
782 }
783
Greg Danielcffb0622020-07-16 13:19:17 -0400784 // Update the offsets in the footprints to be relative to the slice's offset
785 for (int i = 0; i < mipLevelCount; ++i) {
786 placedFootprints[i].Offset += slice.fOffset;
787 }
Jim Van Verthba7f2292020-04-21 08:56:47 -0400788
Greg Daniel69267912020-07-24 10:42:53 -0400789 ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer)->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400790 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
791 placedFootprints.get(), left, top);
792
793 if (mipLevelCount < (int)desc.MipLevels) {
Brian Salomon4cfae3b2020-07-23 10:33:24 -0400794 tex->markMipmapsDirty();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400795 }
796
797 return true;
798}
799
Jim Van Verth9145f782020-04-28 12:01:12 -0400800static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
Jim Van Verth5fba9ae2020-09-21 17:18:04 -0400801 if (!info.fResource.get()) {
Jim Van Verth9145f782020-04-28 12:01:12 -0400802 return false;
803 }
804 return true;
805}
806
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400807static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
808 if (!caps.isFormatTexturable(info.fFormat)) {
809 return false;
810 }
Brian Salomon718ae762020-09-29 16:52:49 -0400811 // We don't support sampling from multisampled textures.
812 if (info.fSampleCount != 1) {
813 return false;
814 }
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400815 return true;
816}
817
818static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
819 int sampleCnt) {
820 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
821 return false;
822 }
823 return true;
824}
825
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400826sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
827 GrWrapOwnership,
828 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400829 GrIOType ioType) {
830 GrD3DTextureResourceInfo textureInfo;
831 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
832 return nullptr;
833 }
834
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400835 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400836 return nullptr;
837 }
838
839 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
840 return nullptr;
841 }
842
843 // TODO: support protected context
844 if (tex.isProtected()) {
845 return nullptr;
846 }
847
848 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
849 SkASSERT(state);
850 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
851 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500852}
853
854sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400855 GrWrapOwnership ownership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500856 GrWrapCacheable wrapType) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400857 return this->onWrapBackendTexture(tex, ownership, wrapType, kRead_GrIOType);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500858}
859
860sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
861 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500862 GrWrapOwnership ownership,
863 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400864 GrD3DTextureResourceInfo textureInfo;
865 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
866 return nullptr;
867 }
868
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400869 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400870 return nullptr;
871 }
872
873 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
874 return nullptr;
875 }
876 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
877 return nullptr;
878 }
879
880 // TODO: support protected context
881 if (tex.isProtected()) {
882 return nullptr;
883 }
884
885 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
886
887 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
888 SkASSERT(state);
889
890 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
891 sampleCnt, cacheable,
892 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500893}
894
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400895sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400896 GrD3DTextureResourceInfo info;
897 if (!rt.getD3DTextureResourceInfo(&info)) {
898 return nullptr;
899 }
900
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400901 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400902 return nullptr;
903 }
904
905 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
906 return nullptr;
907 }
908
909 // TODO: support protected context
910 if (rt.isProtected()) {
911 return nullptr;
912 }
913
914 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
915
916 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
Brian Salomon72c7b982020-10-06 10:07:38 -0400917 this, rt.dimensions(), rt.sampleCnt(), info, std::move(state));
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400918
919 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
920 SkASSERT(!rt.stencilBits());
921 if (tgt) {
922 SkASSERT(tgt->canAttemptStencilAttachment());
923 }
924
925 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500926}
927
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500928sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400929 GrAccessPattern accessPattern, const void* data) {
930 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
931 if (data && buffer) {
932 buffer->updateData(data, sizeInBytes);
933 }
934
935 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500936}
937
Greg Danielc0d69152020-10-08 14:59:00 -0400938sk_sp<GrAttachment> GrD3DGpu::makeStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
939 SkISize dimensions,
940 int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400941 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
Greg Daniele77162e2020-09-21 15:32:11 -0400942 SkASSERT(dimensions.width() >= rt->width());
943 SkASSERT(dimensions.height() >= rt->height());
Jim Van Verth4f51f472020-04-13 11:02:21 -0400944
Greg Daniel8ade5e82020-10-07 13:09:48 -0400945 DXGI_FORMAT sFmt = this->d3dCaps().preferredStencilFormat();
Jim Van Verth4f51f472020-04-13 11:02:21 -0400946
Jim Van Verth4f51f472020-04-13 11:02:21 -0400947 fStats.incStencilAttachmentCreates();
Greg Danielc0d69152020-10-08 14:59:00 -0400948 return GrD3DAttachment::MakeStencil(this, dimensions, numStencilSamples, sFmt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500949}
950
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400951bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
952 SkISize dimensions,
953 GrTexturable texturable,
954 GrRenderable renderable,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400955 GrMipmapped mipMapped,
Brian Salomon72c7b982020-10-06 10:07:38 -0400956 int sampleCnt,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400957 GrD3DTextureResourceInfo* info,
Greg Daniel16032b32020-05-06 15:31:10 -0400958 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400959 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400960
961 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
962 return false;
963 }
964
965 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
966 return false;
967 }
968
969 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
970 return false;
971 }
972
973 int numMipLevels = 1;
Brian Salomon7e67dca2020-07-21 09:27:25 -0400974 if (mipMapped == GrMipmapped::kYes) {
Mike Reed13711eb2020-07-14 17:16:32 -0400975 numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400976 }
977
978 // create the texture
979 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
980 if (renderable == GrRenderable::kYes) {
981 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
982 }
983
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400984 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400985 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
Greg Daniel16032b32020-05-06 15:31:10 -0400986 resourceDesc.Alignment = 0; // use default alignment
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400987 resourceDesc.Width = dimensions.fWidth;
988 resourceDesc.Height = dimensions.fHeight;
989 resourceDesc.DepthOrArraySize = 1;
990 resourceDesc.MipLevels = numMipLevels;
991 resourceDesc.Format = dxgiFormat;
Brian Salomon72c7b982020-10-06 10:07:38 -0400992 resourceDesc.SampleDesc.Count = sampleCnt;
Jim Van Verth765c5922020-08-10 17:23:50 -0400993 resourceDesc.SampleDesc.Quality = DXGI_STANDARD_MULTISAMPLE_QUALITY_PATTERN;
Greg Daniel16032b32020-05-06 15:31:10 -0400994 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400995 resourceDesc.Flags = usageFlags;
996
Jim Van Verth280d4f72020-05-04 10:04:24 -0400997 D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
998 D3D12_CLEAR_VALUE clearValue = {};
999 if (renderable == GrRenderable::kYes) {
1000 clearValue.Format = dxgiFormat;
1001 // Assume transparent black
1002 clearValue.Color[0] = 0;
1003 clearValue.Color[1] = 0;
1004 clearValue.Color[2] = 0;
1005 clearValue.Color[3] = 0;
1006 clearValuePtr = &clearValue;
1007 }
1008
Greg Daniel16032b32020-05-06 15:31:10 -04001009 D3D12_RESOURCE_STATES initialState = (renderable == GrRenderable::kYes)
1010 ? D3D12_RESOURCE_STATE_RENDER_TARGET
1011 : D3D12_RESOURCE_STATE_COPY_DEST;
Jim Van Verth2b9f53e2020-04-14 11:47:34 -04001012 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
Jim Van Verth280d4f72020-05-04 10:04:24 -04001013 isProtected, clearValuePtr, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001014 SkDebugf("Failed to init texture resource info\n");
1015 return false;
1016 }
1017
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001018 return true;
1019}
1020
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001021GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -04001022 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001023 GrRenderable renderable,
Brian Salomon7e67dca2020-07-21 09:27:25 -04001024 GrMipmapped mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -04001025 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001026 const GrD3DCaps& caps = this->d3dCaps();
1027
1028 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
1029 return {};
1030 }
1031
1032 DXGI_FORMAT dxgiFormat;
1033 if (!format.asDxgiFormat(&dxgiFormat)) {
1034 return {};
1035 }
1036
1037 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
1038 if (!caps.isFormatTexturable(dxgiFormat)) {
1039 return {};
1040 }
1041
1042 GrD3DTextureResourceInfo info;
1043 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
Brian Salomon72c7b982020-10-06 10:07:38 -04001044 renderable, mipMapped, 1, &info,
1045 isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001046 return {};
1047 }
1048
1049 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001050}
1051
Brian Salomon05487ab2020-12-23 20:32:22 -05001052static void copy_src_data(char* mapPtr,
1053 DXGI_FORMAT dxgiFormat,
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001054 D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
Brian Salomon05487ab2020-12-23 20:32:22 -05001055 const GrPixmap srcData[],
1056 int numMipLevels) {
Jim Van Verth43a6e172020-06-23 11:59:08 -04001057 SkASSERT(srcData && numMipLevels);
1058 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
1059 SkASSERT(mapPtr);
1060
Greg Daniel0eca74c2020-10-01 13:46:00 -04001061 size_t bytesPerPixel = GrDxgiFormatBytesPerBlock(dxgiFormat);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001062
1063 for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
1064 const size_t trimRowBytes = srcData[currentMipLevel].width() * bytesPerPixel;
1065
1066 // copy data into the buffer, skipping any trailing bytes
1067 char* dst = mapPtr + placedFootprints[currentMipLevel].Offset;
1068 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
1069 srcData[currentMipLevel].addr(), srcData[currentMipLevel].rowBytes(),
1070 trimRowBytes, srcData[currentMipLevel].height());
1071 }
Jim Van Verth43a6e172020-06-23 11:59:08 -04001072}
1073
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001074static bool copy_color_data(const GrD3DCaps& caps, char* mapPtr,
1075 DXGI_FORMAT dxgiFormat, SkISize dimensions,
1076 D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
1077 SkColor4f color) {
Greg Daniel746460e2020-06-30 13:13:53 -04001078 auto colorType = caps.getFormatColorType(dxgiFormat);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001079 if (colorType == GrColorType::kUnknown) {
1080 return false;
1081 }
1082 GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, dimensions);
1083 if (!GrClearImage(ii, mapPtr, placedFootprints[0].Footprint.RowPitch, color)) {
1084 return false;
1085 }
1086
1087 return true;
1088}
1089
Greg Daniel16032b32020-05-06 15:31:10 -04001090bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
1091 sk_sp<GrRefCntedCallback> finishedCallback,
1092 const BackendTextureData* data) {
Jim Van Verth43a6e172020-06-23 11:59:08 -04001093 GrD3DTextureResourceInfo info;
1094 SkAssertResult(backendTexture.getD3DTextureResourceInfo(&info));
1095
1096 sk_sp<GrD3DResourceState> state = backendTexture.getGrD3DResourceState();
1097 SkASSERT(state);
1098 sk_sp<GrD3DTexture> texture =
1099 GrD3DTexture::MakeWrappedTexture(this, backendTexture.dimensions(),
1100 GrWrapCacheable::kNo,
1101 kRW_GrIOType, info, std::move(state));
1102 if (!texture) {
1103 return false;
1104 }
1105
1106 GrD3DDirectCommandList* cmdList = this->currentCommandList();
1107 if (!cmdList) {
1108 return false;
1109 }
1110
1111 texture->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
1112
1113 ID3D12Resource* d3dResource = texture->d3dResource();
1114 SkASSERT(d3dResource);
1115 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
1116 unsigned int mipLevelCount = 1;
Brian Salomon40a40622020-07-21 10:32:07 -04001117 if (backendTexture.fMipmapped == GrMipmapped::kYes) {
Mike Reed13711eb2020-07-14 17:16:32 -04001118 mipLevelCount = SkMipmap::ComputeLevelCount(backendTexture.dimensions().width(),
Jim Van Verth43a6e172020-06-23 11:59:08 -04001119 backendTexture.dimensions().height()) + 1;
1120 }
1121 SkASSERT(mipLevelCount == info.fLevelCount);
1122 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
1123 UINT64 combinedBufferSize;
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001124 SkAutoTMalloc<UINT> numRows(mipLevelCount);
1125 SkAutoTMalloc<UINT64> rowSizeInBytes(mipLevelCount);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001126 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001127 numRows.get(), rowSizeInBytes.get(), &combinedBufferSize);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001128 SkASSERT(combinedBufferSize);
1129 if (data->type() == BackendTextureData::Type::kColor &&
1130 !GrDxgiFormatIsCompressed(info.fFormat) && mipLevelCount > 1) {
1131 // For a single uncompressed color, we reuse the same top-level buffer area for all levels.
1132 combinedBufferSize =
1133 placedFootprints[0].Footprint.RowPitch * placedFootprints[0].Footprint.Height;
1134 for (unsigned int i = 1; i < mipLevelCount; ++i) {
1135 placedFootprints[i].Offset = 0;
1136 placedFootprints[i].Footprint.RowPitch = placedFootprints[0].Footprint.RowPitch;
1137 }
1138 }
1139
Greg Danielcffb0622020-07-16 13:19:17 -04001140 GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
1141 combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
1142 if (!slice.fBuffer) {
Jim Van Verth43a6e172020-06-23 11:59:08 -04001143 return false;
1144 }
Greg Danielcffb0622020-07-16 13:19:17 -04001145
1146 char* bufferData = (char*)slice.fOffsetMapPtr;
Jim Van Verth43a6e172020-06-23 11:59:08 -04001147 SkASSERT(bufferData);
1148
Jim Van Verth43a6e172020-06-23 11:59:08 -04001149 if (data->type() == BackendTextureData::Type::kPixmaps) {
Greg Daniel0eca74c2020-10-01 13:46:00 -04001150 copy_src_data(bufferData, info.fFormat, placedFootprints.get(), data->pixmaps(),
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001151 info.fLevelCount);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001152 } else if (data->type() == BackendTextureData::Type::kCompressed) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001153 copy_compressed_data(bufferData, info.fFormat, placedFootprints.get(), numRows.get(),
1154 rowSizeInBytes.get(), data->compressedData(), info.fLevelCount);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001155 } else {
1156 SkASSERT(data->type() == BackendTextureData::Type::kColor);
1157 SkImage::CompressionType compression =
1158 GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
1159 if (SkImage::CompressionType::kNone == compression) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001160 if (!copy_color_data(this->d3dCaps(), bufferData, info.fFormat,
1161 backendTexture.dimensions(), placedFootprints, data->color())) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001162 return false;
1163 }
Jim Van Verth43a6e172020-06-23 11:59:08 -04001164 } else {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001165 size_t totalCompressedSize = SkCompressedFormatDataSize(compression,
1166 backendTexture.dimensions(),
Brian Salomon40a40622020-07-21 10:32:07 -04001167 backendTexture.hasMipmaps());
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001168 SkAutoTMalloc<char> tempData(totalCompressedSize);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001169 GrFillInCompressedData(compression, backendTexture.dimensions(),
Brian Salomon40a40622020-07-21 10:32:07 -04001170 backendTexture.fMipmapped, tempData, data->color());
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001171 copy_compressed_data(bufferData, info.fFormat, placedFootprints.get(), numRows.get(),
1172 rowSizeInBytes.get(), tempData.get(), info.fLevelCount);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001173 }
1174 }
Jim Van Verth43a6e172020-06-23 11:59:08 -04001175
Greg Danielcffb0622020-07-16 13:19:17 -04001176 // Update the offsets in the footprints to be relative to the slice's offset
1177 for (unsigned int i = 0; i < mipLevelCount; ++i) {
1178 placedFootprints[i].Offset += slice.fOffset;
1179 }
1180
Greg Daniel69267912020-07-24 10:42:53 -04001181 ID3D12Resource* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer)->d3dResource();
Greg Danielcffb0622020-07-16 13:19:17 -04001182 cmdList->copyBufferToTexture(d3dBuffer, texture.get(), mipLevelCount, placedFootprints.get(), 0,
1183 0);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001184
1185 if (finishedCallback) {
1186 this->addFinishedCallback(std::move(finishedCallback));
1187 }
1188
Greg Daniel16032b32020-05-06 15:31:10 -04001189 return true;
1190}
1191
Greg Danielc1ad77c2020-05-06 11:40:03 -04001192GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
Brian Salomon7e67dca2020-07-21 09:27:25 -04001193 SkISize dimensions, const GrBackendFormat& format, GrMipmapped mipMapped,
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001194 GrProtected isProtected) {
1195 return this->onCreateBackendTexture(dimensions, format, GrRenderable::kNo, mipMapped,
1196 isProtected);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001197}
1198
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001199bool GrD3DGpu::onUpdateCompressedBackendTexture(const GrBackendTexture& backendTexture,
Greg Danielaaf738c2020-07-10 09:30:33 -04001200 sk_sp<GrRefCntedCallback> finishedCallback,
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001201 const BackendTextureData* data) {
1202 return this->onUpdateBackendTexture(backendTexture, std::move(finishedCallback), data);
Greg Danielaaf738c2020-07-10 09:30:33 -04001203}
1204
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001205void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001206 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
1207 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001208}
1209
Robert Phillips979b2232020-02-20 10:47:29 -05001210bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
1211 return false;
1212}
1213
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001214#if GR_TEST_UTILS
1215bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001216 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
1217
1218 GrD3DTextureResourceInfo info;
1219 if (!tex.getD3DTextureResourceInfo(&info)) {
1220 return false;
1221 }
Jim Van Verth5fba9ae2020-09-21 17:18:04 -04001222 ID3D12Resource* textureResource = info.fResource.get();
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001223 if (!textureResource) {
1224 return false;
1225 }
1226 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001227}
1228
Brian Salomon72c7b982020-10-06 10:07:38 -04001229GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(SkISize dimensions,
1230 GrColorType colorType,
Brian Salomonf9b00422020-10-08 16:00:14 -04001231 int sampleCnt,
1232 GrProtected isProtected) {
Brian Salomon72c7b982020-10-06 10:07:38 -04001233 if (dimensions.width() > this->caps()->maxRenderTargetSize() ||
1234 dimensions.height() > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -04001235 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001236 }
1237
1238 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
1239
1240 GrD3DTextureResourceInfo info;
Brian Salomon72c7b982020-10-06 10:07:38 -04001241 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kNo,
Brian Salomon7e67dca2020-07-21 09:27:25 -04001242 GrRenderable::kYes, GrMipmapped::kNo,
Brian Salomonf9b00422020-10-08 16:00:14 -04001243 sampleCnt, &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001244 return {};
1245 }
1246
Brian Salomon72c7b982020-10-06 10:07:38 -04001247 return GrBackendRenderTarget(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001248}
1249
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001250void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
1251 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
1252
1253 GrD3DTextureResourceInfo info;
1254 if (rt.getD3DTextureResourceInfo(&info)) {
Brian Salomon725f1582021-02-12 12:10:43 -05001255 this->submitToGpu(true);
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001256 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
1257 // is deleted.
1258 }
1259}
1260
Jim Van Verth9b5e16c2020-04-20 10:45:52 -04001261void GrD3DGpu::testingOnly_startCapture() {
1262 if (fGraphicsAnalysis) {
1263 fGraphicsAnalysis->BeginCapture();
1264 }
1265}
1266
1267void GrD3DGpu::testingOnly_endCapture() {
1268 if (fGraphicsAnalysis) {
1269 fGraphicsAnalysis->EndCapture();
1270 }
1271}
1272#endif
1273
Jim Van Verthc632aa62020-04-17 16:58:20 -04001274///////////////////////////////////////////////////////////////////////////////
1275
Greg Daniela5a6b322020-04-23 12:52:27 -04001276void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -04001277 int numBarriers,
1278 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1279 SkASSERT(fCurrentDirectCommandList);
1280 SkASSERT(resource);
1281
Greg Daniela5a6b322020-04-23 12:52:27 -04001282 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -04001283}
1284
Greg Daniel69267912020-07-24 10:42:53 -04001285void GrD3DGpu::addBufferResourceBarriers(GrD3DBuffer* buffer,
1286 int numBarriers,
1287 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1288 SkASSERT(fCurrentDirectCommandList);
1289 SkASSERT(buffer);
1290
1291 fCurrentDirectCommandList->resourceBarrier(nullptr, numBarriers, barriers);
1292 fCurrentDirectCommandList->addGrBuffer(sk_ref_sp<const GrBuffer>(buffer));
1293}
1294
1295
Greg Daniel9efe3862020-06-11 11:51:06 -04001296void GrD3DGpu::prepareSurfacesForBackendAccessAndStateUpdates(
Adlai Hollerc2bfcff2020-11-06 15:39:36 -05001297 SkSpan<GrSurfaceProxy*> proxies,
Greg Daniel9efe3862020-06-11 11:51:06 -04001298 SkSurface::BackendSurfaceAccess access,
1299 const GrBackendSurfaceMutableState* newState) {
Jim Van Verth682a2f42020-05-13 16:54:09 -04001300 // prepare proxies by transitioning to PRESENT renderState
Adlai Hollerc2bfcff2020-11-06 15:39:36 -05001301 if (!proxies.empty() && access == SkSurface::BackendSurfaceAccess::kPresent) {
Jim Van Verth682a2f42020-05-13 16:54:09 -04001302 GrD3DTextureResource* resource;
Adlai Hollerc2bfcff2020-11-06 15:39:36 -05001303 for (GrSurfaceProxy* proxy : proxies) {
1304 SkASSERT(proxy->isInstantiated());
1305 if (GrTexture* tex = proxy->peekTexture()) {
Jim Van Verth682a2f42020-05-13 16:54:09 -04001306 resource = static_cast<GrD3DTexture*>(tex);
1307 } else {
Adlai Hollerc2bfcff2020-11-06 15:39:36 -05001308 GrRenderTarget* rt = proxy->peekRenderTarget();
Jim Van Verth682a2f42020-05-13 16:54:09 -04001309 SkASSERT(rt);
1310 resource = static_cast<GrD3DRenderTarget*>(rt);
1311 }
1312 resource->prepareForPresent(this);
1313 }
1314 }
1315}
1316
Jim Van Verth1aaf41b2020-07-29 09:24:29 -04001317void GrD3DGpu::takeOwnershipOfBuffer(sk_sp<GrGpuBuffer> buffer) {
Greg Daniel426274b2020-07-20 11:37:38 -04001318 fCurrentDirectCommandList->addGrBuffer(std::move(buffer));
Greg Danielcffb0622020-07-16 13:19:17 -04001319}
1320
Jim Van Verthc632aa62020-04-17 16:58:20 -04001321bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1322 if (syncCpu) {
1323 return this->submitDirectCommandList(SyncQueue::kForce);
1324 } else {
1325 return this->submitDirectCommandList(SyncQueue::kSkip);
1326 }
1327}
Jim Van Verthc1a67b52020-06-25 13:10:29 -04001328
1329std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrD3DGpu::makeSemaphore(bool) {
1330 return GrD3DSemaphore::Make(this);
1331}
1332std::unique_ptr<GrSemaphore> GrD3DGpu::wrapBackendSemaphore(
1333 const GrBackendSemaphore& semaphore,
1334 GrResourceProvider::SemaphoreWrapType,
1335 GrWrapOwnership) {
1336 SkASSERT(this->caps()->semaphoreSupport());
1337 GrD3DFenceInfo fenceInfo;
1338 if (!semaphore.getD3DFenceInfo(&fenceInfo)) {
1339 return nullptr;
1340 }
1341 return GrD3DSemaphore::MakeWrapped(fenceInfo);
1342}
1343
1344void GrD3DGpu::insertSemaphore(GrSemaphore* semaphore) {
Greg Daniel0106fcc2020-07-01 17:40:12 -04001345 SkASSERT(semaphore);
Jim Van Verthc1a67b52020-06-25 13:10:29 -04001346 GrD3DSemaphore* d3dSem = static_cast<GrD3DSemaphore*>(semaphore);
1347 // TODO: Do we need to track the lifetime of this? How do we know it's done?
1348 fQueue->Signal(d3dSem->fence(), d3dSem->value());
1349}
1350
1351void GrD3DGpu::waitSemaphore(GrSemaphore* semaphore) {
Greg Daniel0106fcc2020-07-01 17:40:12 -04001352 SkASSERT(semaphore);
Jim Van Verthc1a67b52020-06-25 13:10:29 -04001353 GrD3DSemaphore* d3dSem = static_cast<GrD3DSemaphore*>(semaphore);
1354 // TODO: Do we need to track the lifetime of this?
1355 fQueue->Wait(d3dSem->fence(), d3dSem->value());
1356}
Jim Van Verth1e6460d2020-06-30 15:47:52 -04001357
1358GrFence SK_WARN_UNUSED_RESULT GrD3DGpu::insertFence() {
Jim Van Verth5fba9ae2020-09-21 17:18:04 -04001359 GR_D3D_CALL_ERRCHECK(fQueue->Signal(fFence.get(), ++fCurrentFenceValue));
Jim Van Verth1e6460d2020-06-30 15:47:52 -04001360 return fCurrentFenceValue;
1361}
1362
1363bool GrD3DGpu::waitFence(GrFence fence) {
Jim Van Verth3b0d7d12020-07-06 11:52:42 -04001364 return (fFence->GetCompletedValue() >= fence);
Jim Van Verth1e6460d2020-06-30 15:47:52 -04001365}
Greg Daniela89b4302021-01-29 10:48:40 -05001366
1367void GrD3DGpu::finishOutstandingGpuWork() {
1368 this->waitForQueueCompletion();
1369}