blob: cfb9bc5f8f6d1983a3486e851fc45882fc0c8ffc [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"
Jim Van Verth96bfeff2020-04-09 14:36:12 -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"
16#include "src/gpu/GrTexturePriv.h"
Jim Van Verthd6ad4802020-04-03 14:59:20 -040017#include "src/gpu/d3d/GrD3DBuffer.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050018#include "src/gpu/d3d/GrD3DCaps.h"
19#include "src/gpu/d3d/GrD3DOpsRenderPass.h"
Jim Van Verthc1a67b52020-06-25 13:10:29 -040020#include "src/gpu/d3d/GrD3DSemaphore.h"
Jim Van Verth4f51f472020-04-13 11:02:21 -040021#include "src/gpu/d3d/GrD3DStencilAttachment.h"
Jim Van Verthaa90dad2020-03-30 15:00:39 -040022#include "src/gpu/d3d/GrD3DTexture.h"
23#include "src/gpu/d3d/GrD3DTextureRenderTarget.h"
24#include "src/gpu/d3d/GrD3DUtil.h"
Greg Daniel5fc5c812020-04-23 10:30:23 -040025#include "src/sksl/SkSLCompiler.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050026
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040027#if GR_TEST_UTILS
28#include <DXProgrammableCapture.h>
29#endif
30
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050031sk_sp<GrGpu> GrD3DGpu::Make(const GrD3DBackendContext& backendContext,
32 const GrContextOptions& contextOptions, GrContext* context) {
33 return sk_sp<GrGpu>(new GrD3DGpu(context, contextOptions, backendContext));
34}
35
Greg Daniel83ed2132020-03-24 13:15:33 -040036// This constant determines how many OutstandingCommandLists are allocated together as a block in
37// the deque. As such it needs to balance allocating too much memory vs. incurring
38// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
39// command lists we expect to see.
40static const int kDefaultOutstandingAllocCnt = 8;
41
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050042GrD3DGpu::GrD3DGpu(GrContext* context, const GrContextOptions& contextOptions,
43 const GrD3DBackendContext& backendContext)
Jim Van Verth03b8ab22020-02-24 11:36:15 -050044 : INHERITED(context)
45 , fDevice(backendContext.fDevice)
Greg Daniel02c45902020-03-09 10:58:09 -040046
47 , fQueue(backendContext.fQueue)
Greg Daniel83ed2132020-03-24 13:15:33 -040048 , fResourceProvider(this)
Greg Daniel5fc5c812020-04-23 10:30:23 -040049 , fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt)
50 , fCompiler(new SkSL::Compiler()) {
Jim Van Verth8ec13302020-02-26 12:59:56 -050051 fCaps.reset(new GrD3DCaps(contextOptions,
Jim Van Verth9aa9a682020-04-01 10:13:48 -040052 backendContext.fAdapter.get(),
53 backendContext.fDevice.get()));
Greg Daniel85da3362020-03-09 15:18:35 -040054
55 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
Greg Daniele52c9782020-03-23 14:18:37 -040056 SkASSERT(fCurrentDirectCommandList);
Greg Daniel83ed2132020-03-24 13:15:33 -040057
58 SkASSERT(fCurrentFenceValue == 0);
59 SkDEBUGCODE(HRESULT hr = ) fDevice->CreateFence(fCurrentFenceValue, D3D12_FENCE_FLAG_NONE,
60 IID_PPV_ARGS(&fFence));
61 SkASSERT(SUCCEEDED(hr));
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040062
63#if GR_TEST_UTILS
64 HRESULT getAnalysis = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&fGraphicsAnalysis));
65 if (FAILED(getAnalysis)) {
66 fGraphicsAnalysis = nullptr;
67 }
68#endif
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050069}
70
Greg Daniel83ed2132020-03-24 13:15:33 -040071GrD3DGpu::~GrD3DGpu() {
72 this->destroyResources();
73}
74
75void GrD3DGpu::destroyResources() {
76 if (fCurrentDirectCommandList) {
77 fCurrentDirectCommandList->close();
Jim Van Verthba7f2292020-04-21 08:56:47 -040078 fCurrentDirectCommandList->reset();
Greg Daniel83ed2132020-03-24 13:15:33 -040079 }
80
81 // We need to make sure everything has finished on the queue.
Jim Van Verthc632aa62020-04-17 16:58:20 -040082 this->waitForQueueCompletion();
Greg Daniel83ed2132020-03-24 13:15:33 -040083
84 SkDEBUGCODE(uint64_t fenceValue = fFence->GetCompletedValue();)
85
86 // We used a placement new for each object in fOutstandingCommandLists, so we're responsible
87 // for calling the destructor on each of them as well.
88 while (!fOutstandingCommandLists.empty()) {
Jim Van Verthf43da142020-06-09 16:34:43 -040089 OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel83ed2132020-03-24 13:15:33 -040090 SkASSERT(list->fFenceValue <= fenceValue);
91 // No reason to recycle the command lists since we are destroying all resources anyways.
92 list->~OutstandingCommandList();
Jim Van Verthf43da142020-06-09 16:34:43 -040093 fOutstandingCommandLists.pop_front();
Greg Daniel83ed2132020-03-24 13:15:33 -040094 }
Jim Van Verthf2788862020-06-03 17:33:12 -040095
96 fResourceProvider.destroyResources();
Greg Daniel83ed2132020-03-24 13:15:33 -040097}
Greg Daniel31a7b072020-02-26 15:31:49 -050098
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050099GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
Robert Phillips96f22372020-05-20 12:31:18 -0400100 GrRenderTarget* rt, GrStencilAttachment*,
101 GrSurfaceOrigin origin, const SkIRect& bounds,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500102 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -0500103 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500104 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -0500105 if (!fCachedOpsRenderPass) {
106 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
107 }
108
109 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
110 return nullptr;
111 }
112 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500113}
114
Jim Van Verthc632aa62020-04-17 16:58:20 -0400115bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
Greg Daniel83ed2132020-03-24 13:15:33 -0400116 SkASSERT(fCurrentDirectCommandList);
117
Jim Van Verth3eadce22020-06-01 11:34:49 -0400118 fResourceProvider.prepForSubmit();
119
Jim Van Verthc632aa62020-04-17 16:58:20 -0400120 GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
121 if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
122 return false;
123 } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
124 if (sync == SyncQueue::kForce) {
125 this->waitForQueueCompletion();
Jim Van Verth682a2f42020-05-13 16:54:09 -0400126 this->checkForFinishedCommandLists();
Jim Van Verthc632aa62020-04-17 16:58:20 -0400127 }
128 return true;
129 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400130
Greg Daniela581a8b2020-06-19 15:22:18 -0400131 // We just submitted the command list so make sure all GrD3DPipelineState's mark their cached
132 // uniform data as dirty.
133 fResourceProvider.markPipelineStateUniformsDirty();
134
Greg Daniel83ed2132020-03-24 13:15:33 -0400135 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
136 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
137
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400138 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400139 SkASSERT(SUCCEEDED(hr));
140
Jim Van Verthc632aa62020-04-17 16:58:20 -0400141 if (sync == SyncQueue::kForce) {
142 this->waitForQueueCompletion();
143 }
144
Greg Daniel83ed2132020-03-24 13:15:33 -0400145 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
146
147 // This should be done after we have a new command list in case the freeing of any resources
148 // held by a finished command list causes us send a new command to the gpu (like changing the
149 // resource state.
150 this->checkForFinishedCommandLists();
151
152 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400153 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400154}
155
156void GrD3DGpu::checkForFinishedCommandLists() {
157 uint64_t currentFenceValue = fFence->GetCompletedValue();
158
159 // Iterate over all the outstanding command lists to see if any have finished. The commands
160 // lists are in order from oldest to newest, so we start at the front to check if their fence
161 // value is less than the last signaled value. If so we pop it off and move onto the next.
162 // Repeat till we find a command list that has not finished yet (and all others afterwards are
163 // also guaranteed to not have finished).
164 SkDeque::F2BIter iter(fOutstandingCommandLists);
165 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
166 while (curList && curList->fFenceValue <= currentFenceValue) {
167 curList = (const OutstandingCommandList*)iter.next();
168 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400169 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400170 // Since we used placement new we are responsible for calling the destructor manually.
171 front->~OutstandingCommandList();
172 fOutstandingCommandLists.pop_front();
173 }
174}
175
Jim Van Verthc632aa62020-04-17 16:58:20 -0400176void GrD3DGpu::waitForQueueCompletion() {
177 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
178 HANDLE fenceEvent;
179 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
180 SkASSERT(fenceEvent);
181 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
182 SkASSERT(SUCCEEDED(hr));
183 WaitForSingleObject(fenceEvent, INFINITE);
184 CloseHandle(fenceEvent);
185 }
186}
187
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500188void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400189 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
190
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500191 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400192 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500193}
194
Greg Danield4928d02020-06-19 11:13:26 -0400195void GrD3DGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
196 GrGpuFinishedContext finishedContext) {
197 SkASSERT(finishedProc);
198 sk_sp<GrRefCntedCallback> finishedCallback(
199 new GrRefCntedCallback(finishedProc, finishedContext));
Jim Van Verth43a6e172020-06-23 11:59:08 -0400200 this->addFinishedCallback(std::move(finishedCallback));
201}
202
203void GrD3DGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) {
204 SkASSERT(finishedCallback);
Greg Danield4928d02020-06-19 11:13:26 -0400205 // Besides the current command list, we also add the finishedCallback to the newest outstanding
206 // command list. Our contract for calling the proc is that all previous submitted command lists
207 // have finished when we call it. However, if our current command list has no work when it is
208 // flushed it will drop its ref to the callback immediately. But the previous work may not have
209 // finished. It is safe to only add the proc to the newest outstanding commandlist cause that
210 // must finish after all previously submitted command lists.
211 OutstandingCommandList* back = (OutstandingCommandList*)fOutstandingCommandLists.back();
212 if (back) {
213 back->fCommandList->addFinishedCallback(finishedCallback);
214 }
215 fCurrentDirectCommandList->addFinishedCallback(std::move(finishedCallback));
216}
217
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500218void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
219 // TODO
220}
221
222sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
223 const GrBackendFormat& format,
224 GrRenderable renderable,
225 int renderTargetSampleCnt,
226 SkBudgeted budgeted,
227 GrProtected isProtected,
228 int mipLevelCount,
229 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400230 DXGI_FORMAT dxgiFormat;
231 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
232 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
233
234 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
235
236 if (renderable == GrRenderable::kYes) {
237 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
238 }
239
240 // This desc refers to the texture that will be read by the client. Thus even if msaa is
241 // requested, this describes the resolved texture. Therefore we always have samples set
242 // to 1.
243 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400244 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400245 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
246 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
247 // might want to manually set alignment to 4KB for smaller textures
248 resourceDesc.Alignment = 0;
249 resourceDesc.Width = dimensions.fWidth;
250 resourceDesc.Height = dimensions.fHeight;
251 resourceDesc.DepthOrArraySize = 1;
252 resourceDesc.MipLevels = mipLevelCount;
253 resourceDesc.Format = dxgiFormat;
254 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400255 // quality levels are only supported for tiled resources so ignore for now
256 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400257 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400258 resourceDesc.Flags = usageFlags;
259
260 GrMipMapsStatus mipMapsStatus =
261 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
262
263 sk_sp<GrD3DTexture> tex;
264 if (renderable == GrRenderable::kYes) {
265 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
266 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
267 mipMapsStatus);
268 } else {
269 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
270 mipMapsStatus);
271 }
272
273 if (!tex) {
274 return nullptr;
275 }
276
277 if (levelClearMask) {
278 // TODO
279 }
280 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500281}
282
283sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
284 const GrBackendFormat& format,
285 SkBudgeted budgeted,
286 GrMipMapped mipMapped,
287 GrProtected isProtected,
288 const void* data, size_t dataSize) {
289 // TODO
290 return nullptr;
291}
292
Jim Van Verth9145f782020-04-28 12:01:12 -0400293static int get_surface_sample_cnt(GrSurface* surf) {
294 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
295 return rt->numSamples();
296 }
297 return 0;
298}
299
300bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
301 const SkIPoint& dstPoint) {
302
303 if (src->isProtected() && !dst->isProtected()) {
304 SkDebugf("Can't copy from protected memory to non-protected");
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400305 return false;
306 }
Jim Van Verth9145f782020-04-28 12:01:12 -0400307
308 int dstSampleCnt = get_surface_sample_cnt(dst);
309 int srcSampleCnt = get_surface_sample_cnt(src);
310
311 GrD3DTextureResource* dstTexResource;
312 GrD3DTextureResource* srcTexResource;
313 GrRenderTarget* dstRT = dst->asRenderTarget();
314 if (dstRT) {
315 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
316 dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
317 } else {
318 SkASSERT(dst->asTexture());
319 dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
320 }
321 GrRenderTarget* srcRT = src->asRenderTarget();
322 if (srcRT) {
323 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
324 srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
325 } else {
326 SkASSERT(src->asTexture());
327 srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
328 }
329
330 DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
331 DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
332
333 if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
334 this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
335 return true;
336 }
337
338 if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
339 this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
340 return true;
341 }
342
343 return false;
344}
345
346void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
347 GrD3DTextureResource* dstResource,
348 GrD3DTextureResource* srcResource,
349 const SkIRect& srcRect, const SkIPoint& dstPoint) {
350#ifdef SK_DEBUG
351 int dstSampleCnt = get_surface_sample_cnt(dst);
352 int srcSampleCnt = get_surface_sample_cnt(src);
353 DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
354 DXGI_FORMAT srcFormat;
355 SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
356 SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
357#endif
358 if (src->isProtected() && !dst->isProtected()) {
359 SkDebugf("Can't copy from protected memory to non-protected");
360 return;
361 }
362
363 dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
364 srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
365
366 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
367 dstLocation.pResource = dstResource->d3dResource();
368 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
369 dstLocation.SubresourceIndex = 0;
370
371 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
372 srcLocation.pResource = srcResource->d3dResource();
373 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
374 srcLocation.SubresourceIndex = 0;
375
376 D3D12_BOX srcBox = {};
377 srcBox.left = srcRect.fLeft;
378 srcBox.top = srcRect.fTop;
379 srcBox.right = srcRect.fRight;
380 srcBox.bottom = srcRect.fBottom;
381 srcBox.front = 0;
382 srcBox.back = 1;
383 // TODO: use copyResource if copying full resource and sizes match
384 fCurrentDirectCommandList->copyTextureRegion(dstResource->resource(),
385 &dstLocation,
386 dstPoint.fX, dstPoint.fY,
387 srcResource->resource(),
388 &srcLocation,
389 &srcBox);
390
391 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
392 srcRect.width(), srcRect.height());
393 // The rect is already in device space so we pass in kTopLeft so no flip is done.
394 this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
395}
396
397void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
398 const SkIPoint& dstPoint) {
399 // TODO
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400400}
401
Jim Van Verthba7f2292020-04-21 08:56:47 -0400402bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
403 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
404 size_t rowBytes) {
405 SkASSERT(surface);
406
407 if (surfaceColorType != dstColorType) {
408 return false;
409 }
410
411 // Set up src location and box
Jim Van Verthc12aad92020-04-24 16:19:01 -0400412 GrD3DTextureResource* texResource = nullptr;
413 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
414 if (rt) {
415 texResource = rt;
416 } else {
417 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
418 }
419
420 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400421 return false;
422 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400423
Jim Van Verthba7f2292020-04-21 08:56:47 -0400424 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400425 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400426 SkASSERT(srcLocation.pResource);
427 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
428 srcLocation.SubresourceIndex = 0;
429
430 D3D12_BOX srcBox = {};
431 srcBox.left = left;
432 srcBox.top = top;
433 srcBox.right = left + width;
434 srcBox.bottom = top + height;
435 srcBox.front = 0;
436 srcBox.back = 1;
437
438 // Set up dst location and create transfer buffer
439 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
440 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400441 UINT64 transferTotalBytes;
442 const UINT64 baseOffset = 0;
443 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
444 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400445 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400446 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400447 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Jim Van Verthc12aad92020-04-24 16:19:01 -0400448 if (this->d3dCaps().bytesPerPixel(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400449 return false;
450 }
451 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400452
453 // TODO: implement some way of reusing buffers instead of making a new one every time.
454 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
455 GrGpuBufferType::kXferGpuToCpu,
456 kDynamic_GrAccessPattern);
457 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
458 dstLocation.pResource = d3dBuf->d3dResource();
459
460 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400461 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400462
463 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
Jim Van Verthc12aad92020-04-24 16:19:01 -0400464 texResource->resource(), &srcLocation, &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400465 this->submitDirectCommandList(SyncQueue::kForce);
466
467 const void* mappedMemory = transferBuffer->map();
468
469 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400470 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400471
472 transferBuffer->unmap();
473
474 return true;
475}
476
477bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
478 GrColorType surfaceColorType, GrColorType srcColorType,
479 const GrMipLevel texels[], int mipLevelCount,
480 bool prepForTexSampling) {
481 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
482 if (!d3dTex) {
483 return false;
484 }
485
486 // Make sure we have at least the base level
487 if (!mipLevelCount || !texels[0].fPixels) {
488 return false;
489 }
490
491 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
492 bool success = false;
493
494 // Need to change the resource state to COPY_DEST in order to upload to it
495 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
496
497 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
498 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
499 mipLevelCount);
500
501 if (prepForTexSampling) {
502 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
503 }
504
505 return success;
506}
507
508bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
509 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
510 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
511 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
512 SkASSERT(1 == mipLevelCount ||
513 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
514
515 // We assume that if the texture has mip levels, we either upload to all the levels or just the
516 // first.
517 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
518
519 if (width == 0 || height == 0) {
520 return false;
521 }
522
523 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
524 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
525
526 ID3D12Resource* d3dResource = tex->d3dResource();
527 SkASSERT(d3dResource);
528 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
529 // Either upload only the first miplevel or all miplevels
530 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
531
532 if (1 == mipLevelCount && !texels[0].fPixels) {
533 return true; // no data to upload
534 }
535
536 for (int i = 0; i < mipLevelCount; ++i) {
537 // We do not allow any gaps in the mip data
538 if (!texels[i].fPixels) {
539 return false;
540 }
541 }
542
543 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400544 UINT64 combinedBufferSize;
545 // We reset the width and height in the description to match our subrectangle size
546 // so we don't end up allocating more space than we need.
547 desc.Width = width;
548 desc.Height = height;
549 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400550 nullptr, nullptr, &combinedBufferSize);
551 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400552 SkASSERT(combinedBufferSize);
553
554 // TODO: do this until we have slices of buttery buffers
555 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
556 GrGpuBufferType::kXferCpuToGpu,
557 kDynamic_GrAccessPattern);
558 if (!transferBuffer) {
559 return false;
560 }
561 char* bufferData = (char*)transferBuffer->map();
562
563 int currentWidth = width;
564 int currentHeight = height;
565 int layerHeight = tex->height();
566
567 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
568 if (texels[currentMipLevel].fPixels) {
569 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
570
Jim Van Verthfdd36852020-04-21 16:29:44 -0400571 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400572 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
573
574 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
575
576 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400577 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400578 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
579 src, srcRowBytes, trimRowBytes, currentHeight);
580 }
581 currentWidth = std::max(1, currentWidth / 2);
582 currentHeight = std::max(1, currentHeight / 2);
583 layerHeight = currentHeight;
584 }
585
586 transferBuffer->unmap();
587
588 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
589 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
590 placedFootprints.get(), left, top);
591
592 if (mipLevelCount < (int)desc.MipLevels) {
593 tex->texturePriv().markMipMapsDirty();
594 }
595
596 return true;
597}
598
Jim Van Verth9145f782020-04-28 12:01:12 -0400599static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
600 if (!info.fResource.get()) {
601 return false;
602 }
603 return true;
604}
605
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400606static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
607 if (!caps.isFormatTexturable(info.fFormat)) {
608 return false;
609 }
610 return true;
611}
612
613static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
614 int sampleCnt) {
615 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
616 return false;
617 }
618 return true;
619}
620
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400621sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
622 GrWrapOwnership,
623 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400624 GrIOType ioType) {
625 GrD3DTextureResourceInfo textureInfo;
626 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
627 return nullptr;
628 }
629
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400630 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400631 return nullptr;
632 }
633
634 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
635 return nullptr;
636 }
637
638 // TODO: support protected context
639 if (tex.isProtected()) {
640 return nullptr;
641 }
642
643 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
644 SkASSERT(state);
645 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
646 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500647}
648
649sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400650 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500651 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400652 GrD3DTextureResourceInfo textureInfo;
653 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
654 return nullptr;
655 }
656
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400657 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400658 return nullptr;
659 }
660
661 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
662 return nullptr;
663 }
664
665 // TODO: support protected context
666 if (tex.isProtected()) {
667 return nullptr;
668 }
669
670 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
671 SkASSERT(state);
672 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
673 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500674}
675
676sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
677 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500678 GrWrapOwnership ownership,
679 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400680 GrD3DTextureResourceInfo textureInfo;
681 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
682 return nullptr;
683 }
684
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400685 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400686 return nullptr;
687 }
688
689 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
690 return nullptr;
691 }
692 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
693 return nullptr;
694 }
695
696 // TODO: support protected context
697 if (tex.isProtected()) {
698 return nullptr;
699 }
700
701 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
702
703 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
704 SkASSERT(state);
705
706 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
707 sampleCnt, cacheable,
708 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500709}
710
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400711sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400712 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
713 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
714 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
715 // creating and owning the MSAA images.
716 if (rt.sampleCnt() > 1) {
717 return nullptr;
718 }
719
720 GrD3DTextureResourceInfo info;
721 if (!rt.getD3DTextureResourceInfo(&info)) {
722 return nullptr;
723 }
724
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400725 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400726 return nullptr;
727 }
728
729 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
730 return nullptr;
731 }
732
733 // TODO: support protected context
734 if (rt.isProtected()) {
735 return nullptr;
736 }
737
738 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
739
740 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
741 this, rt.dimensions(), 1, info, std::move(state));
742
743 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
744 SkASSERT(!rt.stencilBits());
745 if (tgt) {
746 SkASSERT(tgt->canAttemptStencilAttachment());
747 }
748
749 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500750}
751
752sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400753 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400754
755 GrD3DTextureResourceInfo textureInfo;
756 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
757 return nullptr;
758 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400759 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400760 return nullptr;
761 }
762
763 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
764 return nullptr;
765 }
766
767 // TODO: support protected context
768 if (tex.isProtected()) {
769 return nullptr;
770 }
771
772 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
773 if (!sampleCnt) {
774 return nullptr;
775 }
776
777 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
778 SkASSERT(state);
779
780 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
781 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500782}
783
784sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400785 GrAccessPattern accessPattern, const void* data) {
786 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
787 if (data && buffer) {
788 buffer->updateData(data, sizeInBytes);
789 }
790
791 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500792}
793
794GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
795 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400796 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
797 SkASSERT(width >= rt->width());
798 SkASSERT(height >= rt->height());
799
800 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
801
802 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
803 width,
804 height,
805 numStencilSamples,
806 sFmt));
807 fStats.incStencilAttachmentCreates();
808 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500809}
810
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400811bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
812 SkISize dimensions,
813 GrTexturable texturable,
814 GrRenderable renderable,
815 GrMipMapped mipMapped,
816 GrD3DTextureResourceInfo* info,
Greg Daniel16032b32020-05-06 15:31:10 -0400817 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400818 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400819
820 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
821 return false;
822 }
823
824 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
825 return false;
826 }
827
828 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
829 return false;
830 }
831
832 int numMipLevels = 1;
833 if (mipMapped == GrMipMapped::kYes) {
834 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
835 }
836
837 // create the texture
838 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
839 if (renderable == GrRenderable::kYes) {
840 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
841 }
842
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400843 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400844 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
Greg Daniel16032b32020-05-06 15:31:10 -0400845 resourceDesc.Alignment = 0; // use default alignment
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400846 resourceDesc.Width = dimensions.fWidth;
847 resourceDesc.Height = dimensions.fHeight;
848 resourceDesc.DepthOrArraySize = 1;
849 resourceDesc.MipLevels = numMipLevels;
850 resourceDesc.Format = dxgiFormat;
851 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400852 // quality levels are only supported for tiled resources so ignore for now
853 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Greg Daniel16032b32020-05-06 15:31:10 -0400854 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400855 resourceDesc.Flags = usageFlags;
856
Jim Van Verth280d4f72020-05-04 10:04:24 -0400857 D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
858 D3D12_CLEAR_VALUE clearValue = {};
859 if (renderable == GrRenderable::kYes) {
860 clearValue.Format = dxgiFormat;
861 // Assume transparent black
862 clearValue.Color[0] = 0;
863 clearValue.Color[1] = 0;
864 clearValue.Color[2] = 0;
865 clearValue.Color[3] = 0;
866 clearValuePtr = &clearValue;
867 }
868
Greg Daniel16032b32020-05-06 15:31:10 -0400869 D3D12_RESOURCE_STATES initialState = (renderable == GrRenderable::kYes)
870 ? D3D12_RESOURCE_STATE_RENDER_TARGET
871 : D3D12_RESOURCE_STATE_COPY_DEST;
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400872 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
Jim Van Verth280d4f72020-05-04 10:04:24 -0400873 isProtected, clearValuePtr, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400874 SkDebugf("Failed to init texture resource info\n");
875 return false;
876 }
877
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400878 return true;
879}
880
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500881GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400882 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400883 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400884 GrMipMapped mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400885 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400886 this->handleDirtyContext();
887
888 const GrD3DCaps& caps = this->d3dCaps();
889
890 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
891 return {};
892 }
893
894 DXGI_FORMAT dxgiFormat;
895 if (!format.asDxgiFormat(&dxgiFormat)) {
896 return {};
897 }
898
899 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
900 if (!caps.isFormatTexturable(dxgiFormat)) {
901 return {};
902 }
903
904 GrD3DTextureResourceInfo info;
905 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
906 renderable, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400907 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400908 return {};
909 }
910
911 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500912}
913
Jim Van Verth43a6e172020-06-23 11:59:08 -0400914bool copy_src_data(GrD3DGpu* gpu, char* mapPtr, DXGI_FORMAT dxgiFormat,
915 D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
916 const SkPixmap srcData[], int numMipLevels) {
917 SkASSERT(srcData && numMipLevels);
918 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
919 SkASSERT(mapPtr);
920
921 size_t bytesPerPixel = gpu->d3dCaps().bytesPerPixel(dxgiFormat);
922
923 for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
924 const size_t trimRowBytes = srcData[currentMipLevel].width() * bytesPerPixel;
925
926 // copy data into the buffer, skipping any trailing bytes
927 char* dst = mapPtr + placedFootprints[currentMipLevel].Offset;
928 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
929 srcData[currentMipLevel].addr(), srcData[currentMipLevel].rowBytes(),
930 trimRowBytes, srcData[currentMipLevel].height());
931 }
932
933 return true;
934}
935
Greg Daniel746460e2020-06-30 13:13:53 -0400936bool copy_color_data(const GrD3DCaps& caps, char* mapPtr, DXGI_FORMAT dxgiFormat,
937 SkISize dimensions, D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
938 SkColor4f color) {
939 auto colorType = caps.getFormatColorType(dxgiFormat);
Jim Van Verth43a6e172020-06-23 11:59:08 -0400940 if (colorType == GrColorType::kUnknown) {
941 return false;
942 }
943 GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, dimensions);
944 if (!GrClearImage(ii, mapPtr, placedFootprints[0].Footprint.RowPitch, color)) {
945 return false;
946 }
947
948 return true;
949}
950
Greg Daniel16032b32020-05-06 15:31:10 -0400951bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
952 sk_sp<GrRefCntedCallback> finishedCallback,
953 const BackendTextureData* data) {
Jim Van Verth43a6e172020-06-23 11:59:08 -0400954 GrD3DTextureResourceInfo info;
955 SkAssertResult(backendTexture.getD3DTextureResourceInfo(&info));
956
957 sk_sp<GrD3DResourceState> state = backendTexture.getGrD3DResourceState();
958 SkASSERT(state);
959 sk_sp<GrD3DTexture> texture =
960 GrD3DTexture::MakeWrappedTexture(this, backendTexture.dimensions(),
961 GrWrapCacheable::kNo,
962 kRW_GrIOType, info, std::move(state));
963 if (!texture) {
964 return false;
965 }
966
967 GrD3DDirectCommandList* cmdList = this->currentCommandList();
968 if (!cmdList) {
969 return false;
970 }
971
972 texture->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
973
974 ID3D12Resource* d3dResource = texture->d3dResource();
975 SkASSERT(d3dResource);
976 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
977 unsigned int mipLevelCount = 1;
978 if (backendTexture.fMipMapped == GrMipMapped::kYes) {
979 mipLevelCount = SkMipMap::ComputeLevelCount(backendTexture.dimensions().width(),
980 backendTexture.dimensions().height()) + 1;
981 }
982 SkASSERT(mipLevelCount == info.fLevelCount);
983 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
984 UINT64 combinedBufferSize;
985 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
986 nullptr, nullptr, &combinedBufferSize);
987 SkASSERT(combinedBufferSize);
988 if (data->type() == BackendTextureData::Type::kColor &&
989 !GrDxgiFormatIsCompressed(info.fFormat) && mipLevelCount > 1) {
990 // For a single uncompressed color, we reuse the same top-level buffer area for all levels.
991 combinedBufferSize =
992 placedFootprints[0].Footprint.RowPitch * placedFootprints[0].Footprint.Height;
993 for (unsigned int i = 1; i < mipLevelCount; ++i) {
994 placedFootprints[i].Offset = 0;
995 placedFootprints[i].Footprint.RowPitch = placedFootprints[0].Footprint.RowPitch;
996 }
997 }
998
999 // TODO: do this until we have slices of buttery buffers
1000 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
1001 GrGpuBufferType::kXferCpuToGpu,
1002 kDynamic_GrAccessPattern);
1003 if (!transferBuffer) {
1004 return false;
1005 }
1006 char* bufferData = (char*)transferBuffer->map();
1007 SkASSERT(bufferData);
1008
1009 bool result;
1010 if (data->type() == BackendTextureData::Type::kPixmaps) {
1011 result = copy_src_data(this, bufferData, info.fFormat, placedFootprints.get(),
1012 data->pixmaps(), info.fLevelCount);
1013 } else if (data->type() == BackendTextureData::Type::kCompressed) {
1014 memcpy(bufferData, data->compressedData(), data->compressedSize());
1015 result = true;
1016 } else {
1017 SkASSERT(data->type() == BackendTextureData::Type::kColor);
1018 SkImage::CompressionType compression =
1019 GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
1020 if (SkImage::CompressionType::kNone == compression) {
Greg Daniel746460e2020-06-30 13:13:53 -04001021 result = copy_color_data(this->d3dCaps(), bufferData, info.fFormat,
1022 backendTexture.dimensions(),
Jim Van Verth43a6e172020-06-23 11:59:08 -04001023 placedFootprints, data->color());
1024 } else {
1025 GrFillInCompressedData(compression, backendTexture.dimensions(),
1026 backendTexture.fMipMapped, bufferData, data->color());
1027 result = true;
1028 }
1029 }
1030 transferBuffer->unmap();
1031
1032 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
1033 cmdList->copyBufferToTexture(d3dBuffer, texture.get(), mipLevelCount, placedFootprints.get(),
1034 0, 0);
1035
1036 if (finishedCallback) {
1037 this->addFinishedCallback(std::move(finishedCallback));
1038 }
1039
Greg Daniel16032b32020-05-06 15:31:10 -04001040 return true;
1041}
1042
Greg Danielc1ad77c2020-05-06 11:40:03 -04001043GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
1044 SkISize dimensions, const GrBackendFormat& format, GrMipMapped mipMapped,
1045 GrProtected isProtected, sk_sp<GrRefCntedCallback> finishedCallback,
1046 const BackendTextureData* data) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001047 this->handleDirtyContext();
1048
1049 const GrD3DCaps& caps = this->d3dCaps();
1050
1051 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
1052 return {};
1053 }
1054
1055 DXGI_FORMAT dxgiFormat;
1056 if (!format.asDxgiFormat(&dxgiFormat)) {
1057 return {};
1058 }
1059
1060 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
1061 if (!caps.isFormatTexturable(dxgiFormat)) {
1062 return {};
1063 }
1064
1065 GrD3DTextureResourceInfo info;
1066 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
1067 GrRenderable::kNo, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -04001068 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001069 return {};
1070 }
1071
1072 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001073}
1074
1075void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001076 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
1077 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001078}
1079
Robert Phillips979b2232020-02-20 10:47:29 -05001080bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
1081 return false;
1082}
1083
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001084#if GR_TEST_UTILS
1085bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001086 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
1087
1088 GrD3DTextureResourceInfo info;
1089 if (!tex.getD3DTextureResourceInfo(&info)) {
1090 return false;
1091 }
1092 ID3D12Resource* textureResource = info.fResource.get();
1093 if (!textureResource) {
1094 return false;
1095 }
1096 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001097}
1098
1099GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -04001100 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001101 this->handleDirtyContext();
1102
1103 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -04001104 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001105 }
1106
1107 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
1108
1109 GrD3DTextureResourceInfo info;
1110 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
1111 GrRenderable::kYes, GrMipMapped::kNo,
Greg Daniel16032b32020-05-06 15:31:10 -04001112 &info, GrProtected::kNo)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001113 return {};
1114 }
1115
1116 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001117}
1118
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001119void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
1120 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
1121
1122 GrD3DTextureResourceInfo info;
1123 if (rt.getD3DTextureResourceInfo(&info)) {
1124 this->testingOnly_flushGpuAndSync();
1125 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
1126 // is deleted.
1127 }
1128}
1129
1130void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -04001131 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001132}
Jim Van Verthc632aa62020-04-17 16:58:20 -04001133
Jim Van Verth9b5e16c2020-04-20 10:45:52 -04001134void GrD3DGpu::testingOnly_startCapture() {
1135 if (fGraphicsAnalysis) {
1136 fGraphicsAnalysis->BeginCapture();
1137 }
1138}
1139
1140void GrD3DGpu::testingOnly_endCapture() {
1141 if (fGraphicsAnalysis) {
1142 fGraphicsAnalysis->EndCapture();
1143 }
1144}
1145#endif
1146
Jim Van Verthc632aa62020-04-17 16:58:20 -04001147///////////////////////////////////////////////////////////////////////////////
1148
Greg Daniela5a6b322020-04-23 12:52:27 -04001149void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -04001150 int numBarriers,
1151 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1152 SkASSERT(fCurrentDirectCommandList);
1153 SkASSERT(resource);
1154
Greg Daniela5a6b322020-04-23 12:52:27 -04001155 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -04001156}
1157
Greg Daniel9efe3862020-06-11 11:51:06 -04001158void GrD3DGpu::prepareSurfacesForBackendAccessAndStateUpdates(
1159 GrSurfaceProxy* proxies[],
1160 int numProxies,
1161 SkSurface::BackendSurfaceAccess access,
1162 const GrBackendSurfaceMutableState* newState) {
Jim Van Verth682a2f42020-05-13 16:54:09 -04001163 SkASSERT(numProxies >= 0);
1164 SkASSERT(!numProxies || proxies);
1165
1166 // prepare proxies by transitioning to PRESENT renderState
1167 if (numProxies && access == SkSurface::BackendSurfaceAccess::kPresent) {
1168 GrD3DTextureResource* resource;
1169 for (int i = 0; i < numProxies; ++i) {
1170 SkASSERT(proxies[i]->isInstantiated());
1171 if (GrTexture* tex = proxies[i]->peekTexture()) {
1172 resource = static_cast<GrD3DTexture*>(tex);
1173 } else {
1174 GrRenderTarget* rt = proxies[i]->peekRenderTarget();
1175 SkASSERT(rt);
1176 resource = static_cast<GrD3DRenderTarget*>(rt);
1177 }
1178 resource->prepareForPresent(this);
1179 }
1180 }
1181}
1182
Jim Van Verthc632aa62020-04-17 16:58:20 -04001183bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1184 if (syncCpu) {
1185 return this->submitDirectCommandList(SyncQueue::kForce);
1186 } else {
1187 return this->submitDirectCommandList(SyncQueue::kSkip);
1188 }
1189}
Jim Van Verthc1a67b52020-06-25 13:10:29 -04001190
1191std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrD3DGpu::makeSemaphore(bool) {
1192 return GrD3DSemaphore::Make(this);
1193}
1194std::unique_ptr<GrSemaphore> GrD3DGpu::wrapBackendSemaphore(
1195 const GrBackendSemaphore& semaphore,
1196 GrResourceProvider::SemaphoreWrapType,
1197 GrWrapOwnership) {
1198 SkASSERT(this->caps()->semaphoreSupport());
1199 GrD3DFenceInfo fenceInfo;
1200 if (!semaphore.getD3DFenceInfo(&fenceInfo)) {
1201 return nullptr;
1202 }
1203 return GrD3DSemaphore::MakeWrapped(fenceInfo);
1204}
1205
1206void GrD3DGpu::insertSemaphore(GrSemaphore* semaphore) {
1207 GrD3DSemaphore* d3dSem = static_cast<GrD3DSemaphore*>(semaphore);
1208 // TODO: Do we need to track the lifetime of this? How do we know it's done?
1209 fQueue->Signal(d3dSem->fence(), d3dSem->value());
1210}
1211
1212void GrD3DGpu::waitSemaphore(GrSemaphore* semaphore) {
1213 GrD3DSemaphore* d3dSem = static_cast<GrD3DSemaphore*>(semaphore);
1214 // TODO: Do we need to track the lifetime of this?
1215 fQueue->Wait(d3dSem->fence(), d3dSem->value());
1216}