blob: 3c7023ca2f653244cbe8da19f9671699ee697512 [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 Verthc632aa62020-04-17 16:58:20 -040014#include "src/gpu/GrDataUtils.h"
15#include "src/gpu/GrTexturePriv.h"
Jim Van Verthd6ad4802020-04-03 14:59:20 -040016#include "src/gpu/d3d/GrD3DBuffer.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050017#include "src/gpu/d3d/GrD3DCaps.h"
18#include "src/gpu/d3d/GrD3DOpsRenderPass.h"
Jim Van Verth4f51f472020-04-13 11:02:21 -040019#include "src/gpu/d3d/GrD3DStencilAttachment.h"
Jim Van Verthaa90dad2020-03-30 15:00:39 -040020#include "src/gpu/d3d/GrD3DTexture.h"
21#include "src/gpu/d3d/GrD3DTextureRenderTarget.h"
22#include "src/gpu/d3d/GrD3DUtil.h"
Greg Daniel5fc5c812020-04-23 10:30:23 -040023#include "src/sksl/SkSLCompiler.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050024
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040025#if GR_TEST_UTILS
26#include <DXProgrammableCapture.h>
27#endif
28
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050029sk_sp<GrGpu> GrD3DGpu::Make(const GrD3DBackendContext& backendContext,
30 const GrContextOptions& contextOptions, GrContext* context) {
31 return sk_sp<GrGpu>(new GrD3DGpu(context, contextOptions, backendContext));
32}
33
Greg Daniel83ed2132020-03-24 13:15:33 -040034// This constant determines how many OutstandingCommandLists are allocated together as a block in
35// the deque. As such it needs to balance allocating too much memory vs. incurring
36// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
37// command lists we expect to see.
38static const int kDefaultOutstandingAllocCnt = 8;
39
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050040GrD3DGpu::GrD3DGpu(GrContext* context, const GrContextOptions& contextOptions,
41 const GrD3DBackendContext& backendContext)
Jim Van Verth03b8ab22020-02-24 11:36:15 -050042 : INHERITED(context)
43 , fDevice(backendContext.fDevice)
Greg Daniel02c45902020-03-09 10:58:09 -040044
45 , fQueue(backendContext.fQueue)
Greg Daniel83ed2132020-03-24 13:15:33 -040046 , fResourceProvider(this)
Greg Daniel5fc5c812020-04-23 10:30:23 -040047 , fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt)
48 , fCompiler(new SkSL::Compiler()) {
Jim Van Verth8ec13302020-02-26 12:59:56 -050049 fCaps.reset(new GrD3DCaps(contextOptions,
Jim Van Verth9aa9a682020-04-01 10:13:48 -040050 backendContext.fAdapter.get(),
51 backendContext.fDevice.get()));
Greg Daniel85da3362020-03-09 15:18:35 -040052
53 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
Greg Daniele52c9782020-03-23 14:18:37 -040054 SkASSERT(fCurrentDirectCommandList);
Greg Daniel83ed2132020-03-24 13:15:33 -040055
56 SkASSERT(fCurrentFenceValue == 0);
57 SkDEBUGCODE(HRESULT hr = ) fDevice->CreateFence(fCurrentFenceValue, D3D12_FENCE_FLAG_NONE,
58 IID_PPV_ARGS(&fFence));
59 SkASSERT(SUCCEEDED(hr));
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040060
61#if GR_TEST_UTILS
62 HRESULT getAnalysis = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&fGraphicsAnalysis));
63 if (FAILED(getAnalysis)) {
64 fGraphicsAnalysis = nullptr;
65 }
66#endif
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050067}
68
Greg Daniel83ed2132020-03-24 13:15:33 -040069GrD3DGpu::~GrD3DGpu() {
70 this->destroyResources();
71}
72
73void GrD3DGpu::destroyResources() {
74 if (fCurrentDirectCommandList) {
75 fCurrentDirectCommandList->close();
Jim Van Verthba7f2292020-04-21 08:56:47 -040076 fCurrentDirectCommandList->reset();
Greg Daniel83ed2132020-03-24 13:15:33 -040077 }
78
79 // We need to make sure everything has finished on the queue.
Jim Van Verthc632aa62020-04-17 16:58:20 -040080 this->waitForQueueCompletion();
Greg Daniel83ed2132020-03-24 13:15:33 -040081
82 SkDEBUGCODE(uint64_t fenceValue = fFence->GetCompletedValue();)
83
84 // We used a placement new for each object in fOutstandingCommandLists, so we're responsible
85 // for calling the destructor on each of them as well.
86 while (!fOutstandingCommandLists.empty()) {
Jim Van Verthf43da142020-06-09 16:34:43 -040087 OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel83ed2132020-03-24 13:15:33 -040088 SkASSERT(list->fFenceValue <= fenceValue);
89 // No reason to recycle the command lists since we are destroying all resources anyways.
90 list->~OutstandingCommandList();
Jim Van Verthf43da142020-06-09 16:34:43 -040091 fOutstandingCommandLists.pop_front();
Greg Daniel83ed2132020-03-24 13:15:33 -040092 }
Jim Van Verthf2788862020-06-03 17:33:12 -040093
94 fResourceProvider.destroyResources();
Greg Daniel83ed2132020-03-24 13:15:33 -040095}
Greg Daniel31a7b072020-02-26 15:31:49 -050096
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050097GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
Robert Phillips96f22372020-05-20 12:31:18 -040098 GrRenderTarget* rt, GrStencilAttachment*,
99 GrSurfaceOrigin origin, const SkIRect& bounds,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500100 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -0500101 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500102 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -0500103 if (!fCachedOpsRenderPass) {
104 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
105 }
106
107 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
108 return nullptr;
109 }
110 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500111}
112
Jim Van Verthc632aa62020-04-17 16:58:20 -0400113bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
Greg Daniel83ed2132020-03-24 13:15:33 -0400114 SkASSERT(fCurrentDirectCommandList);
115
Jim Van Verth3eadce22020-06-01 11:34:49 -0400116 fResourceProvider.prepForSubmit();
117
Jim Van Verthc632aa62020-04-17 16:58:20 -0400118 GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
119 if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
120 return false;
121 } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
122 if (sync == SyncQueue::kForce) {
123 this->waitForQueueCompletion();
Jim Van Verth682a2f42020-05-13 16:54:09 -0400124 this->checkForFinishedCommandLists();
Jim Van Verthc632aa62020-04-17 16:58:20 -0400125 }
126 return true;
127 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400128
Greg Daniela581a8b2020-06-19 15:22:18 -0400129 // We just submitted the command list so make sure all GrD3DPipelineState's mark their cached
130 // uniform data as dirty.
131 fResourceProvider.markPipelineStateUniformsDirty();
132
Greg Daniel83ed2132020-03-24 13:15:33 -0400133 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
134 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
135
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400136 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400137 SkASSERT(SUCCEEDED(hr));
138
Jim Van Verthc632aa62020-04-17 16:58:20 -0400139 if (sync == SyncQueue::kForce) {
140 this->waitForQueueCompletion();
141 }
142
Greg Daniel83ed2132020-03-24 13:15:33 -0400143 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
144
145 // This should be done after we have a new command list in case the freeing of any resources
146 // held by a finished command list causes us send a new command to the gpu (like changing the
147 // resource state.
148 this->checkForFinishedCommandLists();
149
150 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400151 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400152}
153
154void GrD3DGpu::checkForFinishedCommandLists() {
155 uint64_t currentFenceValue = fFence->GetCompletedValue();
156
157 // Iterate over all the outstanding command lists to see if any have finished. The commands
158 // lists are in order from oldest to newest, so we start at the front to check if their fence
159 // value is less than the last signaled value. If so we pop it off and move onto the next.
160 // Repeat till we find a command list that has not finished yet (and all others afterwards are
161 // also guaranteed to not have finished).
162 SkDeque::F2BIter iter(fOutstandingCommandLists);
163 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
164 while (curList && curList->fFenceValue <= currentFenceValue) {
165 curList = (const OutstandingCommandList*)iter.next();
166 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400167 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400168 // Since we used placement new we are responsible for calling the destructor manually.
169 front->~OutstandingCommandList();
170 fOutstandingCommandLists.pop_front();
171 }
172}
173
Jim Van Verthc632aa62020-04-17 16:58:20 -0400174void GrD3DGpu::waitForQueueCompletion() {
175 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
176 HANDLE fenceEvent;
177 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
178 SkASSERT(fenceEvent);
179 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
180 SkASSERT(SUCCEEDED(hr));
181 WaitForSingleObject(fenceEvent, INFINITE);
182 CloseHandle(fenceEvent);
183 }
184}
185
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500186void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400187 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
188
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500189 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400190 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500191}
192
Greg Danield4928d02020-06-19 11:13:26 -0400193void GrD3DGpu::addFinishedProc(GrGpuFinishedProc finishedProc,
194 GrGpuFinishedContext finishedContext) {
195 SkASSERT(finishedProc);
196 sk_sp<GrRefCntedCallback> finishedCallback(
197 new GrRefCntedCallback(finishedProc, finishedContext));
198 // Besides the current command list, we also add the finishedCallback to the newest outstanding
199 // command list. Our contract for calling the proc is that all previous submitted command lists
200 // have finished when we call it. However, if our current command list has no work when it is
201 // flushed it will drop its ref to the callback immediately. But the previous work may not have
202 // finished. It is safe to only add the proc to the newest outstanding commandlist cause that
203 // must finish after all previously submitted command lists.
204 OutstandingCommandList* back = (OutstandingCommandList*)fOutstandingCommandLists.back();
205 if (back) {
206 back->fCommandList->addFinishedCallback(finishedCallback);
207 }
208 fCurrentDirectCommandList->addFinishedCallback(std::move(finishedCallback));
209}
210
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500211void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
212 // TODO
213}
214
215sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
216 const GrBackendFormat& format,
217 GrRenderable renderable,
218 int renderTargetSampleCnt,
219 SkBudgeted budgeted,
220 GrProtected isProtected,
221 int mipLevelCount,
222 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400223 DXGI_FORMAT dxgiFormat;
224 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
225 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
226
227 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
228
229 if (renderable == GrRenderable::kYes) {
230 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
231 }
232
233 // This desc refers to the texture that will be read by the client. Thus even if msaa is
234 // requested, this describes the resolved texture. Therefore we always have samples set
235 // to 1.
236 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400237 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400238 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
239 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
240 // might want to manually set alignment to 4KB for smaller textures
241 resourceDesc.Alignment = 0;
242 resourceDesc.Width = dimensions.fWidth;
243 resourceDesc.Height = dimensions.fHeight;
244 resourceDesc.DepthOrArraySize = 1;
245 resourceDesc.MipLevels = mipLevelCount;
246 resourceDesc.Format = dxgiFormat;
247 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400248 // quality levels are only supported for tiled resources so ignore for now
249 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400250 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400251 resourceDesc.Flags = usageFlags;
252
253 GrMipMapsStatus mipMapsStatus =
254 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
255
256 sk_sp<GrD3DTexture> tex;
257 if (renderable == GrRenderable::kYes) {
258 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
259 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
260 mipMapsStatus);
261 } else {
262 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
263 mipMapsStatus);
264 }
265
266 if (!tex) {
267 return nullptr;
268 }
269
270 if (levelClearMask) {
271 // TODO
272 }
273 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500274}
275
276sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
277 const GrBackendFormat& format,
278 SkBudgeted budgeted,
279 GrMipMapped mipMapped,
280 GrProtected isProtected,
281 const void* data, size_t dataSize) {
282 // TODO
283 return nullptr;
284}
285
Jim Van Verth9145f782020-04-28 12:01:12 -0400286static int get_surface_sample_cnt(GrSurface* surf) {
287 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
288 return rt->numSamples();
289 }
290 return 0;
291}
292
293bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
294 const SkIPoint& dstPoint) {
295
296 if (src->isProtected() && !dst->isProtected()) {
297 SkDebugf("Can't copy from protected memory to non-protected");
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400298 return false;
299 }
Jim Van Verth9145f782020-04-28 12:01:12 -0400300
301 int dstSampleCnt = get_surface_sample_cnt(dst);
302 int srcSampleCnt = get_surface_sample_cnt(src);
303
304 GrD3DTextureResource* dstTexResource;
305 GrD3DTextureResource* srcTexResource;
306 GrRenderTarget* dstRT = dst->asRenderTarget();
307 if (dstRT) {
308 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
309 dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
310 } else {
311 SkASSERT(dst->asTexture());
312 dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
313 }
314 GrRenderTarget* srcRT = src->asRenderTarget();
315 if (srcRT) {
316 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
317 srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
318 } else {
319 SkASSERT(src->asTexture());
320 srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
321 }
322
323 DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
324 DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
325
326 if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
327 this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
328 return true;
329 }
330
331 if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
332 this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
333 return true;
334 }
335
336 return false;
337}
338
339void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
340 GrD3DTextureResource* dstResource,
341 GrD3DTextureResource* srcResource,
342 const SkIRect& srcRect, const SkIPoint& dstPoint) {
343#ifdef SK_DEBUG
344 int dstSampleCnt = get_surface_sample_cnt(dst);
345 int srcSampleCnt = get_surface_sample_cnt(src);
346 DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
347 DXGI_FORMAT srcFormat;
348 SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
349 SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
350#endif
351 if (src->isProtected() && !dst->isProtected()) {
352 SkDebugf("Can't copy from protected memory to non-protected");
353 return;
354 }
355
356 dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
357 srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
358
359 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
360 dstLocation.pResource = dstResource->d3dResource();
361 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
362 dstLocation.SubresourceIndex = 0;
363
364 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
365 srcLocation.pResource = srcResource->d3dResource();
366 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
367 srcLocation.SubresourceIndex = 0;
368
369 D3D12_BOX srcBox = {};
370 srcBox.left = srcRect.fLeft;
371 srcBox.top = srcRect.fTop;
372 srcBox.right = srcRect.fRight;
373 srcBox.bottom = srcRect.fBottom;
374 srcBox.front = 0;
375 srcBox.back = 1;
376 // TODO: use copyResource if copying full resource and sizes match
377 fCurrentDirectCommandList->copyTextureRegion(dstResource->resource(),
378 &dstLocation,
379 dstPoint.fX, dstPoint.fY,
380 srcResource->resource(),
381 &srcLocation,
382 &srcBox);
383
384 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
385 srcRect.width(), srcRect.height());
386 // The rect is already in device space so we pass in kTopLeft so no flip is done.
387 this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
388}
389
390void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
391 const SkIPoint& dstPoint) {
392 // TODO
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400393}
394
Jim Van Verthba7f2292020-04-21 08:56:47 -0400395bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
396 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
397 size_t rowBytes) {
398 SkASSERT(surface);
399
400 if (surfaceColorType != dstColorType) {
401 return false;
402 }
403
404 // Set up src location and box
Jim Van Verthc12aad92020-04-24 16:19:01 -0400405 GrD3DTextureResource* texResource = nullptr;
406 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
407 if (rt) {
408 texResource = rt;
409 } else {
410 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
411 }
412
413 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400414 return false;
415 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400416
Jim Van Verthba7f2292020-04-21 08:56:47 -0400417 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400418 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400419 SkASSERT(srcLocation.pResource);
420 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
421 srcLocation.SubresourceIndex = 0;
422
423 D3D12_BOX srcBox = {};
424 srcBox.left = left;
425 srcBox.top = top;
426 srcBox.right = left + width;
427 srcBox.bottom = top + height;
428 srcBox.front = 0;
429 srcBox.back = 1;
430
431 // Set up dst location and create transfer buffer
432 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
433 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400434 UINT64 transferTotalBytes;
435 const UINT64 baseOffset = 0;
436 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
437 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400438 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400439 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400440 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Jim Van Verthc12aad92020-04-24 16:19:01 -0400441 if (this->d3dCaps().bytesPerPixel(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400442 return false;
443 }
444 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400445
446 // TODO: implement some way of reusing buffers instead of making a new one every time.
447 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
448 GrGpuBufferType::kXferGpuToCpu,
449 kDynamic_GrAccessPattern);
450 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
451 dstLocation.pResource = d3dBuf->d3dResource();
452
453 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400454 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400455
456 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
Jim Van Verthc12aad92020-04-24 16:19:01 -0400457 texResource->resource(), &srcLocation, &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400458 this->submitDirectCommandList(SyncQueue::kForce);
459
460 const void* mappedMemory = transferBuffer->map();
461
462 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400463 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400464
465 transferBuffer->unmap();
466
467 return true;
468}
469
470bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
471 GrColorType surfaceColorType, GrColorType srcColorType,
472 const GrMipLevel texels[], int mipLevelCount,
473 bool prepForTexSampling) {
474 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
475 if (!d3dTex) {
476 return false;
477 }
478
479 // Make sure we have at least the base level
480 if (!mipLevelCount || !texels[0].fPixels) {
481 return false;
482 }
483
484 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
485 bool success = false;
486
487 // Need to change the resource state to COPY_DEST in order to upload to it
488 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
489
490 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
491 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
492 mipLevelCount);
493
494 if (prepForTexSampling) {
495 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
496 }
497
498 return success;
499}
500
501bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
502 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
503 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
504 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
505 SkASSERT(1 == mipLevelCount ||
506 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
507
508 // We assume that if the texture has mip levels, we either upload to all the levels or just the
509 // first.
510 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
511
512 if (width == 0 || height == 0) {
513 return false;
514 }
515
516 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
517 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
518
519 ID3D12Resource* d3dResource = tex->d3dResource();
520 SkASSERT(d3dResource);
521 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
522 // Either upload only the first miplevel or all miplevels
523 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
524
525 if (1 == mipLevelCount && !texels[0].fPixels) {
526 return true; // no data to upload
527 }
528
529 for (int i = 0; i < mipLevelCount; ++i) {
530 // We do not allow any gaps in the mip data
531 if (!texels[i].fPixels) {
532 return false;
533 }
534 }
535
536 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400537 UINT64 combinedBufferSize;
538 // We reset the width and height in the description to match our subrectangle size
539 // so we don't end up allocating more space than we need.
540 desc.Width = width;
541 desc.Height = height;
542 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400543 nullptr, nullptr, &combinedBufferSize);
544 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400545 SkASSERT(combinedBufferSize);
546
547 // TODO: do this until we have slices of buttery buffers
548 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
549 GrGpuBufferType::kXferCpuToGpu,
550 kDynamic_GrAccessPattern);
551 if (!transferBuffer) {
552 return false;
553 }
554 char* bufferData = (char*)transferBuffer->map();
555
556 int currentWidth = width;
557 int currentHeight = height;
558 int layerHeight = tex->height();
559
560 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
561 if (texels[currentMipLevel].fPixels) {
562 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
563
Jim Van Verthfdd36852020-04-21 16:29:44 -0400564 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400565 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
566
567 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
568
569 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400570 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400571 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
572 src, srcRowBytes, trimRowBytes, currentHeight);
573 }
574 currentWidth = std::max(1, currentWidth / 2);
575 currentHeight = std::max(1, currentHeight / 2);
576 layerHeight = currentHeight;
577 }
578
579 transferBuffer->unmap();
580
581 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
582 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
583 placedFootprints.get(), left, top);
584
585 if (mipLevelCount < (int)desc.MipLevels) {
586 tex->texturePriv().markMipMapsDirty();
587 }
588
589 return true;
590}
591
Jim Van Verth9145f782020-04-28 12:01:12 -0400592static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
593 if (!info.fResource.get()) {
594 return false;
595 }
596 return true;
597}
598
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400599static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
600 if (!caps.isFormatTexturable(info.fFormat)) {
601 return false;
602 }
603 return true;
604}
605
606static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
607 int sampleCnt) {
608 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
609 return false;
610 }
611 return true;
612}
613
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400614sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
615 GrWrapOwnership,
616 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400617 GrIOType ioType) {
618 GrD3DTextureResourceInfo textureInfo;
619 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
620 return nullptr;
621 }
622
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400623 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400624 return nullptr;
625 }
626
627 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
628 return nullptr;
629 }
630
631 // TODO: support protected context
632 if (tex.isProtected()) {
633 return nullptr;
634 }
635
636 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
637 SkASSERT(state);
638 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
639 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500640}
641
642sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400643 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500644 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400645 GrD3DTextureResourceInfo textureInfo;
646 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
647 return nullptr;
648 }
649
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400650 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400651 return nullptr;
652 }
653
654 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
655 return nullptr;
656 }
657
658 // TODO: support protected context
659 if (tex.isProtected()) {
660 return nullptr;
661 }
662
663 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
664 SkASSERT(state);
665 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
666 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500667}
668
669sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
670 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500671 GrWrapOwnership ownership,
672 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400673 GrD3DTextureResourceInfo textureInfo;
674 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
675 return nullptr;
676 }
677
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400678 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400679 return nullptr;
680 }
681
682 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
683 return nullptr;
684 }
685 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
686 return nullptr;
687 }
688
689 // TODO: support protected context
690 if (tex.isProtected()) {
691 return nullptr;
692 }
693
694 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
695
696 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
697 SkASSERT(state);
698
699 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
700 sampleCnt, cacheable,
701 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500702}
703
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400704sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400705 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
706 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
707 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
708 // creating and owning the MSAA images.
709 if (rt.sampleCnt() > 1) {
710 return nullptr;
711 }
712
713 GrD3DTextureResourceInfo info;
714 if (!rt.getD3DTextureResourceInfo(&info)) {
715 return nullptr;
716 }
717
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400718 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400719 return nullptr;
720 }
721
722 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
723 return nullptr;
724 }
725
726 // TODO: support protected context
727 if (rt.isProtected()) {
728 return nullptr;
729 }
730
731 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
732
733 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
734 this, rt.dimensions(), 1, info, std::move(state));
735
736 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
737 SkASSERT(!rt.stencilBits());
738 if (tgt) {
739 SkASSERT(tgt->canAttemptStencilAttachment());
740 }
741
742 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500743}
744
745sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400746 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400747
748 GrD3DTextureResourceInfo textureInfo;
749 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
750 return nullptr;
751 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400752 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400753 return nullptr;
754 }
755
756 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
757 return nullptr;
758 }
759
760 // TODO: support protected context
761 if (tex.isProtected()) {
762 return nullptr;
763 }
764
765 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
766 if (!sampleCnt) {
767 return nullptr;
768 }
769
770 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
771 SkASSERT(state);
772
773 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
774 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500775}
776
777sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400778 GrAccessPattern accessPattern, const void* data) {
779 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
780 if (data && buffer) {
781 buffer->updateData(data, sizeInBytes);
782 }
783
784 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500785}
786
787GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
788 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400789 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
790 SkASSERT(width >= rt->width());
791 SkASSERT(height >= rt->height());
792
793 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
794
795 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
796 width,
797 height,
798 numStencilSamples,
799 sFmt));
800 fStats.incStencilAttachmentCreates();
801 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500802}
803
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400804bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
805 SkISize dimensions,
806 GrTexturable texturable,
807 GrRenderable renderable,
808 GrMipMapped mipMapped,
809 GrD3DTextureResourceInfo* info,
Greg Daniel16032b32020-05-06 15:31:10 -0400810 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400811 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400812
813 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
814 return false;
815 }
816
817 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
818 return false;
819 }
820
821 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
822 return false;
823 }
824
825 int numMipLevels = 1;
826 if (mipMapped == GrMipMapped::kYes) {
827 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
828 }
829
830 // create the texture
831 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
832 if (renderable == GrRenderable::kYes) {
833 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
834 }
835
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400836 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400837 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
Greg Daniel16032b32020-05-06 15:31:10 -0400838 resourceDesc.Alignment = 0; // use default alignment
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400839 resourceDesc.Width = dimensions.fWidth;
840 resourceDesc.Height = dimensions.fHeight;
841 resourceDesc.DepthOrArraySize = 1;
842 resourceDesc.MipLevels = numMipLevels;
843 resourceDesc.Format = dxgiFormat;
844 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400845 // quality levels are only supported for tiled resources so ignore for now
846 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Greg Daniel16032b32020-05-06 15:31:10 -0400847 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400848 resourceDesc.Flags = usageFlags;
849
Jim Van Verth280d4f72020-05-04 10:04:24 -0400850 D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
851 D3D12_CLEAR_VALUE clearValue = {};
852 if (renderable == GrRenderable::kYes) {
853 clearValue.Format = dxgiFormat;
854 // Assume transparent black
855 clearValue.Color[0] = 0;
856 clearValue.Color[1] = 0;
857 clearValue.Color[2] = 0;
858 clearValue.Color[3] = 0;
859 clearValuePtr = &clearValue;
860 }
861
Greg Daniel16032b32020-05-06 15:31:10 -0400862 D3D12_RESOURCE_STATES initialState = (renderable == GrRenderable::kYes)
863 ? D3D12_RESOURCE_STATE_RENDER_TARGET
864 : D3D12_RESOURCE_STATE_COPY_DEST;
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400865 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
Jim Van Verth280d4f72020-05-04 10:04:24 -0400866 isProtected, clearValuePtr, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400867 SkDebugf("Failed to init texture resource info\n");
868 return false;
869 }
870
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400871 return true;
872}
873
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500874GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400875 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400876 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400877 GrMipMapped mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400878 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400879 this->handleDirtyContext();
880
881 const GrD3DCaps& caps = this->d3dCaps();
882
883 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
884 return {};
885 }
886
887 DXGI_FORMAT dxgiFormat;
888 if (!format.asDxgiFormat(&dxgiFormat)) {
889 return {};
890 }
891
892 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
893 if (!caps.isFormatTexturable(dxgiFormat)) {
894 return {};
895 }
896
897 GrD3DTextureResourceInfo info;
898 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
899 renderable, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400900 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400901 return {};
902 }
903
904 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500905}
906
Greg Daniel16032b32020-05-06 15:31:10 -0400907bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
908 sk_sp<GrRefCntedCallback> finishedCallback,
909 const BackendTextureData* data) {
910 // TODO: handle finishedCallback and data upload
911 return true;
912}
913
Greg Danielc1ad77c2020-05-06 11:40:03 -0400914GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
915 SkISize dimensions, const GrBackendFormat& format, GrMipMapped mipMapped,
916 GrProtected isProtected, sk_sp<GrRefCntedCallback> finishedCallback,
917 const BackendTextureData* data) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400918 this->handleDirtyContext();
919
920 const GrD3DCaps& caps = this->d3dCaps();
921
922 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
923 return {};
924 }
925
926 DXGI_FORMAT dxgiFormat;
927 if (!format.asDxgiFormat(&dxgiFormat)) {
928 return {};
929 }
930
931 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
932 if (!caps.isFormatTexturable(dxgiFormat)) {
933 return {};
934 }
935
936 GrD3DTextureResourceInfo info;
937 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
938 GrRenderable::kNo, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400939 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400940 return {};
941 }
942
943 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500944}
945
946void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400947 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
948 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500949}
950
Robert Phillips979b2232020-02-20 10:47:29 -0500951bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
952 return false;
953}
954
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500955#if GR_TEST_UTILS
956bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400957 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
958
959 GrD3DTextureResourceInfo info;
960 if (!tex.getD3DTextureResourceInfo(&info)) {
961 return false;
962 }
963 ID3D12Resource* textureResource = info.fResource.get();
964 if (!textureResource) {
965 return false;
966 }
967 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500968}
969
970GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400971 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400972 this->handleDirtyContext();
973
974 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400975 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400976 }
977
978 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
979
980 GrD3DTextureResourceInfo info;
981 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
982 GrRenderable::kYes, GrMipMapped::kNo,
Greg Daniel16032b32020-05-06 15:31:10 -0400983 &info, GrProtected::kNo)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400984 return {};
985 }
986
987 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500988}
989
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400990void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
991 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
992
993 GrD3DTextureResourceInfo info;
994 if (rt.getD3DTextureResourceInfo(&info)) {
995 this->testingOnly_flushGpuAndSync();
996 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
997 // is deleted.
998 }
999}
1000
1001void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -04001002 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001003}
Jim Van Verthc632aa62020-04-17 16:58:20 -04001004
Jim Van Verth9b5e16c2020-04-20 10:45:52 -04001005void GrD3DGpu::testingOnly_startCapture() {
1006 if (fGraphicsAnalysis) {
1007 fGraphicsAnalysis->BeginCapture();
1008 }
1009}
1010
1011void GrD3DGpu::testingOnly_endCapture() {
1012 if (fGraphicsAnalysis) {
1013 fGraphicsAnalysis->EndCapture();
1014 }
1015}
1016#endif
1017
Jim Van Verthc632aa62020-04-17 16:58:20 -04001018///////////////////////////////////////////////////////////////////////////////
1019
Greg Daniela5a6b322020-04-23 12:52:27 -04001020void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -04001021 int numBarriers,
1022 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1023 SkASSERT(fCurrentDirectCommandList);
1024 SkASSERT(resource);
1025
Greg Daniela5a6b322020-04-23 12:52:27 -04001026 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -04001027}
1028
Greg Daniel9efe3862020-06-11 11:51:06 -04001029void GrD3DGpu::prepareSurfacesForBackendAccessAndStateUpdates(
1030 GrSurfaceProxy* proxies[],
1031 int numProxies,
1032 SkSurface::BackendSurfaceAccess access,
1033 const GrBackendSurfaceMutableState* newState) {
Jim Van Verth682a2f42020-05-13 16:54:09 -04001034 SkASSERT(numProxies >= 0);
1035 SkASSERT(!numProxies || proxies);
1036
1037 // prepare proxies by transitioning to PRESENT renderState
1038 if (numProxies && access == SkSurface::BackendSurfaceAccess::kPresent) {
1039 GrD3DTextureResource* resource;
1040 for (int i = 0; i < numProxies; ++i) {
1041 SkASSERT(proxies[i]->isInstantiated());
1042 if (GrTexture* tex = proxies[i]->peekTexture()) {
1043 resource = static_cast<GrD3DTexture*>(tex);
1044 } else {
1045 GrRenderTarget* rt = proxies[i]->peekRenderTarget();
1046 SkASSERT(rt);
1047 resource = static_cast<GrD3DRenderTarget*>(rt);
1048 }
1049 resource->prepareForPresent(this);
1050 }
1051 }
1052}
1053
Jim Van Verthc632aa62020-04-17 16:58:20 -04001054bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1055 if (syncCpu) {
1056 return this->submitDirectCommandList(SyncQueue::kForce);
1057 } else {
1058 return this->submitDirectCommandList(SyncQueue::kSkip);
1059 }
1060}