blob: 605f44eaa7522d0837a0739b6b935b43f0d9386f [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).
Jim Van Verthdd3b4012020-06-30 15:28:17 -0400164 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
165 while (front && front->fFenceValue <= currentFenceValue) {
166 std::unique_ptr<GrD3DDirectCommandList> currList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400167 // Since we used placement new we are responsible for calling the destructor manually.
168 front->~OutstandingCommandList();
169 fOutstandingCommandLists.pop_front();
Jim Van Verthdd3b4012020-06-30 15:28:17 -0400170 fResourceProvider.recycleDirectCommandList(std::move(currList));
171 front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel83ed2132020-03-24 13:15:33 -0400172 }
173}
174
Jim Van Verthc632aa62020-04-17 16:58:20 -0400175void GrD3DGpu::waitForQueueCompletion() {
176 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
177 HANDLE fenceEvent;
178 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
179 SkASSERT(fenceEvent);
180 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
181 SkASSERT(SUCCEEDED(hr));
182 WaitForSingleObject(fenceEvent, INFINITE);
183 CloseHandle(fenceEvent);
184 }
185}
186
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500187void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400188 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
189
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500190 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400191 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500192}
193
Greg Danield4928d02020-06-19 11:13:26 -0400194void GrD3DGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
195 GrGpuFinishedContext finishedContext) {
196 SkASSERT(finishedProc);
197 sk_sp<GrRefCntedCallback> finishedCallback(
198 new GrRefCntedCallback(finishedProc, finishedContext));
Jim Van Verth43a6e172020-06-23 11:59:08 -0400199 this->addFinishedCallback(std::move(finishedCallback));
200}
201
202void GrD3DGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) {
203 SkASSERT(finishedCallback);
Greg Danield4928d02020-06-19 11:13:26 -0400204 // Besides the current command list, we also add the finishedCallback to the newest outstanding
205 // command list. Our contract for calling the proc is that all previous submitted command lists
206 // have finished when we call it. However, if our current command list has no work when it is
207 // flushed it will drop its ref to the callback immediately. But the previous work may not have
208 // finished. It is safe to only add the proc to the newest outstanding commandlist cause that
209 // must finish after all previously submitted command lists.
210 OutstandingCommandList* back = (OutstandingCommandList*)fOutstandingCommandLists.back();
211 if (back) {
212 back->fCommandList->addFinishedCallback(finishedCallback);
213 }
214 fCurrentDirectCommandList->addFinishedCallback(std::move(finishedCallback));
215}
216
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500217void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
218 // TODO
219}
220
221sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
222 const GrBackendFormat& format,
223 GrRenderable renderable,
224 int renderTargetSampleCnt,
225 SkBudgeted budgeted,
226 GrProtected isProtected,
227 int mipLevelCount,
228 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400229 DXGI_FORMAT dxgiFormat;
230 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
231 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
232
233 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
234
235 if (renderable == GrRenderable::kYes) {
236 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
237 }
238
239 // This desc refers to the texture that will be read by the client. Thus even if msaa is
240 // requested, this describes the resolved texture. Therefore we always have samples set
241 // to 1.
242 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400243 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400244 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
245 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
246 // might want to manually set alignment to 4KB for smaller textures
247 resourceDesc.Alignment = 0;
248 resourceDesc.Width = dimensions.fWidth;
249 resourceDesc.Height = dimensions.fHeight;
250 resourceDesc.DepthOrArraySize = 1;
251 resourceDesc.MipLevels = mipLevelCount;
252 resourceDesc.Format = dxgiFormat;
253 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400254 // quality levels are only supported for tiled resources so ignore for now
255 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400256 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400257 resourceDesc.Flags = usageFlags;
258
259 GrMipMapsStatus mipMapsStatus =
260 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
261
262 sk_sp<GrD3DTexture> tex;
263 if (renderable == GrRenderable::kYes) {
264 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
265 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
266 mipMapsStatus);
267 } else {
268 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
269 mipMapsStatus);
270 }
271
272 if (!tex) {
273 return nullptr;
274 }
275
276 if (levelClearMask) {
277 // TODO
278 }
279 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500280}
281
282sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
283 const GrBackendFormat& format,
284 SkBudgeted budgeted,
285 GrMipMapped mipMapped,
286 GrProtected isProtected,
287 const void* data, size_t dataSize) {
288 // TODO
289 return nullptr;
290}
291
Jim Van Verth9145f782020-04-28 12:01:12 -0400292static int get_surface_sample_cnt(GrSurface* surf) {
293 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
294 return rt->numSamples();
295 }
296 return 0;
297}
298
299bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
300 const SkIPoint& dstPoint) {
301
302 if (src->isProtected() && !dst->isProtected()) {
303 SkDebugf("Can't copy from protected memory to non-protected");
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400304 return false;
305 }
Jim Van Verth9145f782020-04-28 12:01:12 -0400306
307 int dstSampleCnt = get_surface_sample_cnt(dst);
308 int srcSampleCnt = get_surface_sample_cnt(src);
309
310 GrD3DTextureResource* dstTexResource;
311 GrD3DTextureResource* srcTexResource;
312 GrRenderTarget* dstRT = dst->asRenderTarget();
313 if (dstRT) {
314 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
315 dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
316 } else {
317 SkASSERT(dst->asTexture());
318 dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
319 }
320 GrRenderTarget* srcRT = src->asRenderTarget();
321 if (srcRT) {
322 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
323 srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
324 } else {
325 SkASSERT(src->asTexture());
326 srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
327 }
328
329 DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
330 DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
331
332 if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
333 this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
334 return true;
335 }
336
337 if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
338 this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
339 return true;
340 }
341
342 return false;
343}
344
345void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
346 GrD3DTextureResource* dstResource,
347 GrD3DTextureResource* srcResource,
348 const SkIRect& srcRect, const SkIPoint& dstPoint) {
349#ifdef SK_DEBUG
350 int dstSampleCnt = get_surface_sample_cnt(dst);
351 int srcSampleCnt = get_surface_sample_cnt(src);
352 DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
353 DXGI_FORMAT srcFormat;
354 SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
355 SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
356#endif
357 if (src->isProtected() && !dst->isProtected()) {
358 SkDebugf("Can't copy from protected memory to non-protected");
359 return;
360 }
361
362 dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
363 srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
364
365 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
366 dstLocation.pResource = dstResource->d3dResource();
367 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
368 dstLocation.SubresourceIndex = 0;
369
370 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
371 srcLocation.pResource = srcResource->d3dResource();
372 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
373 srcLocation.SubresourceIndex = 0;
374
375 D3D12_BOX srcBox = {};
376 srcBox.left = srcRect.fLeft;
377 srcBox.top = srcRect.fTop;
378 srcBox.right = srcRect.fRight;
379 srcBox.bottom = srcRect.fBottom;
380 srcBox.front = 0;
381 srcBox.back = 1;
382 // TODO: use copyResource if copying full resource and sizes match
383 fCurrentDirectCommandList->copyTextureRegion(dstResource->resource(),
384 &dstLocation,
385 dstPoint.fX, dstPoint.fY,
386 srcResource->resource(),
387 &srcLocation,
388 &srcBox);
389
390 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
391 srcRect.width(), srcRect.height());
392 // The rect is already in device space so we pass in kTopLeft so no flip is done.
393 this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
394}
395
396void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
397 const SkIPoint& dstPoint) {
398 // TODO
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400399}
400
Jim Van Verthba7f2292020-04-21 08:56:47 -0400401bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
402 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
403 size_t rowBytes) {
404 SkASSERT(surface);
405
406 if (surfaceColorType != dstColorType) {
407 return false;
408 }
409
410 // Set up src location and box
Jim Van Verthc12aad92020-04-24 16:19:01 -0400411 GrD3DTextureResource* texResource = nullptr;
412 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
413 if (rt) {
414 texResource = rt;
415 } else {
416 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
417 }
418
419 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400420 return false;
421 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400422
Jim Van Verthba7f2292020-04-21 08:56:47 -0400423 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400424 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400425 SkASSERT(srcLocation.pResource);
426 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
427 srcLocation.SubresourceIndex = 0;
428
429 D3D12_BOX srcBox = {};
430 srcBox.left = left;
431 srcBox.top = top;
432 srcBox.right = left + width;
433 srcBox.bottom = top + height;
434 srcBox.front = 0;
435 srcBox.back = 1;
436
437 // Set up dst location and create transfer buffer
438 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
439 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400440 UINT64 transferTotalBytes;
441 const UINT64 baseOffset = 0;
442 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
443 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400444 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400445 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400446 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Jim Van Verthc12aad92020-04-24 16:19:01 -0400447 if (this->d3dCaps().bytesPerPixel(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400448 return false;
449 }
450 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400451
452 // TODO: implement some way of reusing buffers instead of making a new one every time.
453 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
454 GrGpuBufferType::kXferGpuToCpu,
455 kDynamic_GrAccessPattern);
456 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
457 dstLocation.pResource = d3dBuf->d3dResource();
458
459 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400460 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400461
462 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
Jim Van Verthc12aad92020-04-24 16:19:01 -0400463 texResource->resource(), &srcLocation, &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400464 this->submitDirectCommandList(SyncQueue::kForce);
465
466 const void* mappedMemory = transferBuffer->map();
467
468 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400469 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400470
471 transferBuffer->unmap();
472
473 return true;
474}
475
476bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
477 GrColorType surfaceColorType, GrColorType srcColorType,
478 const GrMipLevel texels[], int mipLevelCount,
479 bool prepForTexSampling) {
480 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
481 if (!d3dTex) {
482 return false;
483 }
484
485 // Make sure we have at least the base level
486 if (!mipLevelCount || !texels[0].fPixels) {
487 return false;
488 }
489
490 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
491 bool success = false;
492
493 // Need to change the resource state to COPY_DEST in order to upload to it
494 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
495
496 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
497 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
498 mipLevelCount);
499
500 if (prepForTexSampling) {
501 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
502 }
503
504 return success;
505}
506
507bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
508 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
509 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
510 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
511 SkASSERT(1 == mipLevelCount ||
512 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
513
514 // We assume that if the texture has mip levels, we either upload to all the levels or just the
515 // first.
516 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
517
518 if (width == 0 || height == 0) {
519 return false;
520 }
521
522 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
523 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
524
525 ID3D12Resource* d3dResource = tex->d3dResource();
526 SkASSERT(d3dResource);
527 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
528 // Either upload only the first miplevel or all miplevels
529 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
530
531 if (1 == mipLevelCount && !texels[0].fPixels) {
532 return true; // no data to upload
533 }
534
535 for (int i = 0; i < mipLevelCount; ++i) {
536 // We do not allow any gaps in the mip data
537 if (!texels[i].fPixels) {
538 return false;
539 }
540 }
541
542 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400543 UINT64 combinedBufferSize;
544 // We reset the width and height in the description to match our subrectangle size
545 // so we don't end up allocating more space than we need.
546 desc.Width = width;
547 desc.Height = height;
548 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400549 nullptr, nullptr, &combinedBufferSize);
550 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400551 SkASSERT(combinedBufferSize);
552
553 // TODO: do this until we have slices of buttery buffers
554 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
555 GrGpuBufferType::kXferCpuToGpu,
556 kDynamic_GrAccessPattern);
557 if (!transferBuffer) {
558 return false;
559 }
560 char* bufferData = (char*)transferBuffer->map();
561
562 int currentWidth = width;
563 int currentHeight = height;
564 int layerHeight = tex->height();
565
566 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
567 if (texels[currentMipLevel].fPixels) {
568 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
569
Jim Van Verthfdd36852020-04-21 16:29:44 -0400570 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400571 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
572
573 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
574
575 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400576 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400577 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
578 src, srcRowBytes, trimRowBytes, currentHeight);
579 }
580 currentWidth = std::max(1, currentWidth / 2);
581 currentHeight = std::max(1, currentHeight / 2);
582 layerHeight = currentHeight;
583 }
584
585 transferBuffer->unmap();
586
587 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
588 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
589 placedFootprints.get(), left, top);
590
591 if (mipLevelCount < (int)desc.MipLevels) {
592 tex->texturePriv().markMipMapsDirty();
593 }
594
595 return true;
596}
597
Jim Van Verth9145f782020-04-28 12:01:12 -0400598static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
599 if (!info.fResource.get()) {
600 return false;
601 }
602 return true;
603}
604
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400605static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
606 if (!caps.isFormatTexturable(info.fFormat)) {
607 return false;
608 }
609 return true;
610}
611
612static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
613 int sampleCnt) {
614 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
615 return false;
616 }
617 return true;
618}
619
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400620sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
621 GrWrapOwnership,
622 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400623 GrIOType ioType) {
624 GrD3DTextureResourceInfo textureInfo;
625 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
626 return nullptr;
627 }
628
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400629 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400630 return nullptr;
631 }
632
633 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
634 return nullptr;
635 }
636
637 // TODO: support protected context
638 if (tex.isProtected()) {
639 return nullptr;
640 }
641
642 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
643 SkASSERT(state);
644 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
645 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500646}
647
648sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400649 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500650 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400651 GrD3DTextureResourceInfo textureInfo;
652 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
653 return nullptr;
654 }
655
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400656 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400657 return nullptr;
658 }
659
660 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
661 return nullptr;
662 }
663
664 // TODO: support protected context
665 if (tex.isProtected()) {
666 return nullptr;
667 }
668
669 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
670 SkASSERT(state);
671 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
672 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500673}
674
675sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
676 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500677 GrWrapOwnership ownership,
678 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400679 GrD3DTextureResourceInfo textureInfo;
680 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
681 return nullptr;
682 }
683
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400684 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400685 return nullptr;
686 }
687
688 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
689 return nullptr;
690 }
691 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
692 return nullptr;
693 }
694
695 // TODO: support protected context
696 if (tex.isProtected()) {
697 return nullptr;
698 }
699
700 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
701
702 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
703 SkASSERT(state);
704
705 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
706 sampleCnt, cacheable,
707 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500708}
709
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400710sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400711 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
712 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
713 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
714 // creating and owning the MSAA images.
715 if (rt.sampleCnt() > 1) {
716 return nullptr;
717 }
718
719 GrD3DTextureResourceInfo info;
720 if (!rt.getD3DTextureResourceInfo(&info)) {
721 return nullptr;
722 }
723
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400724 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400725 return nullptr;
726 }
727
728 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
729 return nullptr;
730 }
731
732 // TODO: support protected context
733 if (rt.isProtected()) {
734 return nullptr;
735 }
736
737 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
738
739 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
740 this, rt.dimensions(), 1, info, std::move(state));
741
742 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
743 SkASSERT(!rt.stencilBits());
744 if (tgt) {
745 SkASSERT(tgt->canAttemptStencilAttachment());
746 }
747
748 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500749}
750
751sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400752 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400753
754 GrD3DTextureResourceInfo textureInfo;
755 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
756 return nullptr;
757 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400758 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400759 return nullptr;
760 }
761
762 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
763 return nullptr;
764 }
765
766 // TODO: support protected context
767 if (tex.isProtected()) {
768 return nullptr;
769 }
770
771 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
772 if (!sampleCnt) {
773 return nullptr;
774 }
775
776 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
777 SkASSERT(state);
778
779 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
780 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500781}
782
783sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400784 GrAccessPattern accessPattern, const void* data) {
785 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
786 if (data && buffer) {
787 buffer->updateData(data, sizeInBytes);
788 }
789
790 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500791}
792
793GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
794 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400795 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
796 SkASSERT(width >= rt->width());
797 SkASSERT(height >= rt->height());
798
799 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
800
801 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
802 width,
803 height,
804 numStencilSamples,
805 sFmt));
806 fStats.incStencilAttachmentCreates();
807 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500808}
809
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400810bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
811 SkISize dimensions,
812 GrTexturable texturable,
813 GrRenderable renderable,
814 GrMipMapped mipMapped,
815 GrD3DTextureResourceInfo* info,
Greg Daniel16032b32020-05-06 15:31:10 -0400816 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400817 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400818
819 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
820 return false;
821 }
822
823 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
824 return false;
825 }
826
827 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
828 return false;
829 }
830
831 int numMipLevels = 1;
832 if (mipMapped == GrMipMapped::kYes) {
833 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
834 }
835
836 // create the texture
837 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
838 if (renderable == GrRenderable::kYes) {
839 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
840 }
841
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400842 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400843 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
Greg Daniel16032b32020-05-06 15:31:10 -0400844 resourceDesc.Alignment = 0; // use default alignment
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400845 resourceDesc.Width = dimensions.fWidth;
846 resourceDesc.Height = dimensions.fHeight;
847 resourceDesc.DepthOrArraySize = 1;
848 resourceDesc.MipLevels = numMipLevels;
849 resourceDesc.Format = dxgiFormat;
850 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400851 // quality levels are only supported for tiled resources so ignore for now
852 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Greg Daniel16032b32020-05-06 15:31:10 -0400853 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400854 resourceDesc.Flags = usageFlags;
855
Jim Van Verth280d4f72020-05-04 10:04:24 -0400856 D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
857 D3D12_CLEAR_VALUE clearValue = {};
858 if (renderable == GrRenderable::kYes) {
859 clearValue.Format = dxgiFormat;
860 // Assume transparent black
861 clearValue.Color[0] = 0;
862 clearValue.Color[1] = 0;
863 clearValue.Color[2] = 0;
864 clearValue.Color[3] = 0;
865 clearValuePtr = &clearValue;
866 }
867
Greg Daniel16032b32020-05-06 15:31:10 -0400868 D3D12_RESOURCE_STATES initialState = (renderable == GrRenderable::kYes)
869 ? D3D12_RESOURCE_STATE_RENDER_TARGET
870 : D3D12_RESOURCE_STATE_COPY_DEST;
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400871 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
Jim Van Verth280d4f72020-05-04 10:04:24 -0400872 isProtected, clearValuePtr, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400873 SkDebugf("Failed to init texture resource info\n");
874 return false;
875 }
876
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400877 return true;
878}
879
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500880GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400881 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400882 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400883 GrMipMapped mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400884 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400885 this->handleDirtyContext();
886
887 const GrD3DCaps& caps = this->d3dCaps();
888
889 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
890 return {};
891 }
892
893 DXGI_FORMAT dxgiFormat;
894 if (!format.asDxgiFormat(&dxgiFormat)) {
895 return {};
896 }
897
898 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
899 if (!caps.isFormatTexturable(dxgiFormat)) {
900 return {};
901 }
902
903 GrD3DTextureResourceInfo info;
904 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
905 renderable, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400906 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400907 return {};
908 }
909
910 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500911}
912
Jim Van Verth43a6e172020-06-23 11:59:08 -0400913bool copy_src_data(GrD3DGpu* gpu, char* mapPtr, DXGI_FORMAT dxgiFormat,
914 D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
915 const SkPixmap srcData[], int numMipLevels) {
916 SkASSERT(srcData && numMipLevels);
917 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
918 SkASSERT(mapPtr);
919
920 size_t bytesPerPixel = gpu->d3dCaps().bytesPerPixel(dxgiFormat);
921
922 for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
923 const size_t trimRowBytes = srcData[currentMipLevel].width() * bytesPerPixel;
924
925 // copy data into the buffer, skipping any trailing bytes
926 char* dst = mapPtr + placedFootprints[currentMipLevel].Offset;
927 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
928 srcData[currentMipLevel].addr(), srcData[currentMipLevel].rowBytes(),
929 trimRowBytes, srcData[currentMipLevel].height());
930 }
931
932 return true;
933}
934
Greg Daniel746460e2020-06-30 13:13:53 -0400935bool copy_color_data(const GrD3DCaps& caps, char* mapPtr, DXGI_FORMAT dxgiFormat,
936 SkISize dimensions, D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
937 SkColor4f color) {
938 auto colorType = caps.getFormatColorType(dxgiFormat);
Jim Van Verth43a6e172020-06-23 11:59:08 -0400939 if (colorType == GrColorType::kUnknown) {
940 return false;
941 }
942 GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, dimensions);
943 if (!GrClearImage(ii, mapPtr, placedFootprints[0].Footprint.RowPitch, color)) {
944 return false;
945 }
946
947 return true;
948}
949
Greg Daniel16032b32020-05-06 15:31:10 -0400950bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
951 sk_sp<GrRefCntedCallback> finishedCallback,
952 const BackendTextureData* data) {
Jim Van Verth43a6e172020-06-23 11:59:08 -0400953 GrD3DTextureResourceInfo info;
954 SkAssertResult(backendTexture.getD3DTextureResourceInfo(&info));
955
956 sk_sp<GrD3DResourceState> state = backendTexture.getGrD3DResourceState();
957 SkASSERT(state);
958 sk_sp<GrD3DTexture> texture =
959 GrD3DTexture::MakeWrappedTexture(this, backendTexture.dimensions(),
960 GrWrapCacheable::kNo,
961 kRW_GrIOType, info, std::move(state));
962 if (!texture) {
963 return false;
964 }
965
966 GrD3DDirectCommandList* cmdList = this->currentCommandList();
967 if (!cmdList) {
968 return false;
969 }
970
971 texture->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
972
973 ID3D12Resource* d3dResource = texture->d3dResource();
974 SkASSERT(d3dResource);
975 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
976 unsigned int mipLevelCount = 1;
977 if (backendTexture.fMipMapped == GrMipMapped::kYes) {
978 mipLevelCount = SkMipMap::ComputeLevelCount(backendTexture.dimensions().width(),
979 backendTexture.dimensions().height()) + 1;
980 }
981 SkASSERT(mipLevelCount == info.fLevelCount);
982 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
983 UINT64 combinedBufferSize;
984 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
985 nullptr, nullptr, &combinedBufferSize);
986 SkASSERT(combinedBufferSize);
987 if (data->type() == BackendTextureData::Type::kColor &&
988 !GrDxgiFormatIsCompressed(info.fFormat) && mipLevelCount > 1) {
989 // For a single uncompressed color, we reuse the same top-level buffer area for all levels.
990 combinedBufferSize =
991 placedFootprints[0].Footprint.RowPitch * placedFootprints[0].Footprint.Height;
992 for (unsigned int i = 1; i < mipLevelCount; ++i) {
993 placedFootprints[i].Offset = 0;
994 placedFootprints[i].Footprint.RowPitch = placedFootprints[0].Footprint.RowPitch;
995 }
996 }
997
998 // TODO: do this until we have slices of buttery buffers
999 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
1000 GrGpuBufferType::kXferCpuToGpu,
1001 kDynamic_GrAccessPattern);
1002 if (!transferBuffer) {
1003 return false;
1004 }
1005 char* bufferData = (char*)transferBuffer->map();
1006 SkASSERT(bufferData);
1007
1008 bool result;
1009 if (data->type() == BackendTextureData::Type::kPixmaps) {
1010 result = copy_src_data(this, bufferData, info.fFormat, placedFootprints.get(),
1011 data->pixmaps(), info.fLevelCount);
1012 } else if (data->type() == BackendTextureData::Type::kCompressed) {
1013 memcpy(bufferData, data->compressedData(), data->compressedSize());
1014 result = true;
1015 } else {
1016 SkASSERT(data->type() == BackendTextureData::Type::kColor);
1017 SkImage::CompressionType compression =
1018 GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
1019 if (SkImage::CompressionType::kNone == compression) {
Greg Daniel746460e2020-06-30 13:13:53 -04001020 result = copy_color_data(this->d3dCaps(), bufferData, info.fFormat,
1021 backendTexture.dimensions(),
Jim Van Verth43a6e172020-06-23 11:59:08 -04001022 placedFootprints, data->color());
1023 } else {
1024 GrFillInCompressedData(compression, backendTexture.dimensions(),
1025 backendTexture.fMipMapped, bufferData, data->color());
1026 result = true;
1027 }
1028 }
1029 transferBuffer->unmap();
1030
1031 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
1032 cmdList->copyBufferToTexture(d3dBuffer, texture.get(), mipLevelCount, placedFootprints.get(),
1033 0, 0);
1034
1035 if (finishedCallback) {
1036 this->addFinishedCallback(std::move(finishedCallback));
1037 }
1038
Greg Daniel16032b32020-05-06 15:31:10 -04001039 return true;
1040}
1041
Greg Danielc1ad77c2020-05-06 11:40:03 -04001042GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
1043 SkISize dimensions, const GrBackendFormat& format, GrMipMapped mipMapped,
1044 GrProtected isProtected, sk_sp<GrRefCntedCallback> finishedCallback,
1045 const BackendTextureData* data) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001046 this->handleDirtyContext();
1047
1048 const GrD3DCaps& caps = this->d3dCaps();
1049
1050 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
1051 return {};
1052 }
1053
1054 DXGI_FORMAT dxgiFormat;
1055 if (!format.asDxgiFormat(&dxgiFormat)) {
1056 return {};
1057 }
1058
1059 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
1060 if (!caps.isFormatTexturable(dxgiFormat)) {
1061 return {};
1062 }
1063
1064 GrD3DTextureResourceInfo info;
1065 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
1066 GrRenderable::kNo, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -04001067 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001068 return {};
1069 }
1070
1071 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001072}
1073
1074void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001075 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
1076 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001077}
1078
Robert Phillips979b2232020-02-20 10:47:29 -05001079bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
1080 return false;
1081}
1082
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001083#if GR_TEST_UTILS
1084bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001085 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
1086
1087 GrD3DTextureResourceInfo info;
1088 if (!tex.getD3DTextureResourceInfo(&info)) {
1089 return false;
1090 }
1091 ID3D12Resource* textureResource = info.fResource.get();
1092 if (!textureResource) {
1093 return false;
1094 }
1095 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001096}
1097
1098GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -04001099 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001100 this->handleDirtyContext();
1101
1102 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -04001103 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001104 }
1105
1106 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
1107
1108 GrD3DTextureResourceInfo info;
1109 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
1110 GrRenderable::kYes, GrMipMapped::kNo,
Greg Daniel16032b32020-05-06 15:31:10 -04001111 &info, GrProtected::kNo)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001112 return {};
1113 }
1114
1115 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001116}
1117
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001118void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
1119 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
1120
1121 GrD3DTextureResourceInfo info;
1122 if (rt.getD3DTextureResourceInfo(&info)) {
1123 this->testingOnly_flushGpuAndSync();
1124 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
1125 // is deleted.
1126 }
1127}
1128
1129void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -04001130 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001131}
Jim Van Verthc632aa62020-04-17 16:58:20 -04001132
Jim Van Verth9b5e16c2020-04-20 10:45:52 -04001133void GrD3DGpu::testingOnly_startCapture() {
1134 if (fGraphicsAnalysis) {
1135 fGraphicsAnalysis->BeginCapture();
1136 }
1137}
1138
1139void GrD3DGpu::testingOnly_endCapture() {
1140 if (fGraphicsAnalysis) {
1141 fGraphicsAnalysis->EndCapture();
1142 }
1143}
1144#endif
1145
Jim Van Verthc632aa62020-04-17 16:58:20 -04001146///////////////////////////////////////////////////////////////////////////////
1147
Greg Daniela5a6b322020-04-23 12:52:27 -04001148void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -04001149 int numBarriers,
1150 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1151 SkASSERT(fCurrentDirectCommandList);
1152 SkASSERT(resource);
1153
Greg Daniela5a6b322020-04-23 12:52:27 -04001154 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -04001155}
1156
Greg Daniel9efe3862020-06-11 11:51:06 -04001157void GrD3DGpu::prepareSurfacesForBackendAccessAndStateUpdates(
1158 GrSurfaceProxy* proxies[],
1159 int numProxies,
1160 SkSurface::BackendSurfaceAccess access,
1161 const GrBackendSurfaceMutableState* newState) {
Jim Van Verth682a2f42020-05-13 16:54:09 -04001162 SkASSERT(numProxies >= 0);
1163 SkASSERT(!numProxies || proxies);
1164
1165 // prepare proxies by transitioning to PRESENT renderState
1166 if (numProxies && access == SkSurface::BackendSurfaceAccess::kPresent) {
1167 GrD3DTextureResource* resource;
1168 for (int i = 0; i < numProxies; ++i) {
1169 SkASSERT(proxies[i]->isInstantiated());
1170 if (GrTexture* tex = proxies[i]->peekTexture()) {
1171 resource = static_cast<GrD3DTexture*>(tex);
1172 } else {
1173 GrRenderTarget* rt = proxies[i]->peekRenderTarget();
1174 SkASSERT(rt);
1175 resource = static_cast<GrD3DRenderTarget*>(rt);
1176 }
1177 resource->prepareForPresent(this);
1178 }
1179 }
1180}
1181
Jim Van Verthc632aa62020-04-17 16:58:20 -04001182bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1183 if (syncCpu) {
1184 return this->submitDirectCommandList(SyncQueue::kForce);
1185 } else {
1186 return this->submitDirectCommandList(SyncQueue::kSkip);
1187 }
1188}
Jim Van Verthc1a67b52020-06-25 13:10:29 -04001189
1190std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrD3DGpu::makeSemaphore(bool) {
1191 return GrD3DSemaphore::Make(this);
1192}
1193std::unique_ptr<GrSemaphore> GrD3DGpu::wrapBackendSemaphore(
1194 const GrBackendSemaphore& semaphore,
1195 GrResourceProvider::SemaphoreWrapType,
1196 GrWrapOwnership) {
1197 SkASSERT(this->caps()->semaphoreSupport());
1198 GrD3DFenceInfo fenceInfo;
1199 if (!semaphore.getD3DFenceInfo(&fenceInfo)) {
1200 return nullptr;
1201 }
1202 return GrD3DSemaphore::MakeWrapped(fenceInfo);
1203}
1204
1205void GrD3DGpu::insertSemaphore(GrSemaphore* semaphore) {
1206 GrD3DSemaphore* d3dSem = static_cast<GrD3DSemaphore*>(semaphore);
1207 // TODO: Do we need to track the lifetime of this? How do we know it's done?
1208 fQueue->Signal(d3dSem->fence(), d3dSem->value());
1209}
1210
1211void GrD3DGpu::waitSemaphore(GrSemaphore* semaphore) {
1212 GrD3DSemaphore* d3dSem = static_cast<GrD3DSemaphore*>(semaphore);
1213 // TODO: Do we need to track the lifetime of this?
1214 fQueue->Wait(d3dSem->fence(), d3dSem->value());
1215}