blob: 89dd76c964decf2c8da265db1f0eb01983080442 [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()) {
87 OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.back();
88 SkASSERT(list->fFenceValue <= fenceValue);
89 // No reason to recycle the command lists since we are destroying all resources anyways.
90 list->~OutstandingCommandList();
91 fOutstandingCommandLists.pop_back();
92 }
93}
Greg Daniel31a7b072020-02-26 15:31:49 -050094
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050095GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
96 GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds,
97 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -050098 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050099 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -0500100 if (!fCachedOpsRenderPass) {
101 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
102 }
103
104 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
105 return nullptr;
106 }
107 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500108}
109
Jim Van Verthc632aa62020-04-17 16:58:20 -0400110bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
Greg Daniel83ed2132020-03-24 13:15:33 -0400111 SkASSERT(fCurrentDirectCommandList);
112
Jim Van Verthc632aa62020-04-17 16:58:20 -0400113 GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
114 if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
115 return false;
116 } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
117 if (sync == SyncQueue::kForce) {
118 this->waitForQueueCompletion();
119 }
120 return true;
121 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400122
123 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
124 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
125
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400126 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400127 SkASSERT(SUCCEEDED(hr));
128
Jim Van Verthc632aa62020-04-17 16:58:20 -0400129 if (sync == SyncQueue::kForce) {
130 this->waitForQueueCompletion();
131 }
132
Greg Daniel83ed2132020-03-24 13:15:33 -0400133 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
134
135 // This should be done after we have a new command list in case the freeing of any resources
136 // held by a finished command list causes us send a new command to the gpu (like changing the
137 // resource state.
138 this->checkForFinishedCommandLists();
139
140 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400141 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400142}
143
144void GrD3DGpu::checkForFinishedCommandLists() {
145 uint64_t currentFenceValue = fFence->GetCompletedValue();
146
147 // Iterate over all the outstanding command lists to see if any have finished. The commands
148 // lists are in order from oldest to newest, so we start at the front to check if their fence
149 // value is less than the last signaled value. If so we pop it off and move onto the next.
150 // Repeat till we find a command list that has not finished yet (and all others afterwards are
151 // also guaranteed to not have finished).
152 SkDeque::F2BIter iter(fOutstandingCommandLists);
153 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
154 while (curList && curList->fFenceValue <= currentFenceValue) {
155 curList = (const OutstandingCommandList*)iter.next();
156 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400157 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400158 // Since we used placement new we are responsible for calling the destructor manually.
159 front->~OutstandingCommandList();
160 fOutstandingCommandLists.pop_front();
161 }
162}
163
Jim Van Verthc632aa62020-04-17 16:58:20 -0400164void GrD3DGpu::waitForQueueCompletion() {
165 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
166 HANDLE fenceEvent;
167 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
168 SkASSERT(fenceEvent);
169 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
170 SkASSERT(SUCCEEDED(hr));
171 WaitForSingleObject(fenceEvent, INFINITE);
172 CloseHandle(fenceEvent);
173 }
174}
175
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500176void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400177 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
178
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500179 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400180 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500181}
182
183void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
184 // TODO
185}
186
187sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
188 const GrBackendFormat& format,
189 GrRenderable renderable,
190 int renderTargetSampleCnt,
191 SkBudgeted budgeted,
192 GrProtected isProtected,
193 int mipLevelCount,
194 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400195 DXGI_FORMAT dxgiFormat;
196 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
197 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
198
199 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
200
201 if (renderable == GrRenderable::kYes) {
202 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
203 }
204
205 // This desc refers to the texture that will be read by the client. Thus even if msaa is
206 // requested, this describes the resolved texture. Therefore we always have samples set
207 // to 1.
208 SkASSERT(mipLevelCount > 0);
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400209 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400210 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
211 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
212 // might want to manually set alignment to 4KB for smaller textures
213 resourceDesc.Alignment = 0;
214 resourceDesc.Width = dimensions.fWidth;
215 resourceDesc.Height = dimensions.fHeight;
216 resourceDesc.DepthOrArraySize = 1;
217 resourceDesc.MipLevels = mipLevelCount;
218 resourceDesc.Format = dxgiFormat;
219 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400220 // quality levels are only supported for tiled resources so ignore for now
221 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400222 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400223 resourceDesc.Flags = usageFlags;
224
225 GrMipMapsStatus mipMapsStatus =
226 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
227
228 sk_sp<GrD3DTexture> tex;
229 if (renderable == GrRenderable::kYes) {
230 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
231 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
232 mipMapsStatus);
233 } else {
234 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
235 mipMapsStatus);
236 }
237
238 if (!tex) {
239 return nullptr;
240 }
241
242 if (levelClearMask) {
243 // TODO
244 }
245 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500246}
247
248sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
249 const GrBackendFormat& format,
250 SkBudgeted budgeted,
251 GrMipMapped mipMapped,
252 GrProtected isProtected,
253 const void* data, size_t dataSize) {
254 // TODO
255 return nullptr;
256}
257
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400258static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400259 if (!info.fResource.get()) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400260 return false;
261 }
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400262 return true;
263}
264
Jim Van Verthba7f2292020-04-21 08:56:47 -0400265bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
266 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
267 size_t rowBytes) {
268 SkASSERT(surface);
269
270 if (surfaceColorType != dstColorType) {
271 return false;
272 }
273
274 // Set up src location and box
275 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
276 if (!d3dTex) {
277 return false;
278 }
279 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
280 srcLocation.pResource = d3dTex->d3dResource();
281 SkASSERT(srcLocation.pResource);
282 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
283 srcLocation.SubresourceIndex = 0;
284
285 D3D12_BOX srcBox = {};
286 srcBox.left = left;
287 srcBox.top = top;
288 srcBox.right = left + width;
289 srcBox.bottom = top + height;
290 srcBox.front = 0;
291 srcBox.back = 1;
292
293 // Set up dst location and create transfer buffer
294 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
295 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400296 UINT64 transferTotalBytes;
297 const UINT64 baseOffset = 0;
298 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
299 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400300 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400301 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400302 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
303 if (this->d3dCaps().bytesPerPixel(d3dTex->dxgiFormat()) != bpp) {
304 return false;
305 }
306 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400307
308 // TODO: implement some way of reusing buffers instead of making a new one every time.
309 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
310 GrGpuBufferType::kXferGpuToCpu,
311 kDynamic_GrAccessPattern);
312 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
313 dstLocation.pResource = d3dBuf->d3dResource();
314
315 // Need to change the resource state to COPY_SOURCE in order to download from it
316 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
317
318 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
319 d3dTex->resource(), &srcLocation, &srcBox);
320 this->submitDirectCommandList(SyncQueue::kForce);
321
322 const void* mappedMemory = transferBuffer->map();
323
324 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400325 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400326
327 transferBuffer->unmap();
328
329 return true;
330}
331
332bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
333 GrColorType surfaceColorType, GrColorType srcColorType,
334 const GrMipLevel texels[], int mipLevelCount,
335 bool prepForTexSampling) {
336 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
337 if (!d3dTex) {
338 return false;
339 }
340
341 // Make sure we have at least the base level
342 if (!mipLevelCount || !texels[0].fPixels) {
343 return false;
344 }
345
346 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
347 bool success = false;
348
349 // Need to change the resource state to COPY_DEST in order to upload to it
350 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
351
352 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
353 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
354 mipLevelCount);
355
356 if (prepForTexSampling) {
357 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
358 }
359
360 return success;
361}
362
363bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
364 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
365 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
366 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
367 SkASSERT(1 == mipLevelCount ||
368 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
369
370 // We assume that if the texture has mip levels, we either upload to all the levels or just the
371 // first.
372 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
373
374 if (width == 0 || height == 0) {
375 return false;
376 }
377
378 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
379 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
380
381 ID3D12Resource* d3dResource = tex->d3dResource();
382 SkASSERT(d3dResource);
383 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
384 // Either upload only the first miplevel or all miplevels
385 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
386
387 if (1 == mipLevelCount && !texels[0].fPixels) {
388 return true; // no data to upload
389 }
390
391 for (int i = 0; i < mipLevelCount; ++i) {
392 // We do not allow any gaps in the mip data
393 if (!texels[i].fPixels) {
394 return false;
395 }
396 }
397
398 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400399 UINT64 combinedBufferSize;
400 // We reset the width and height in the description to match our subrectangle size
401 // so we don't end up allocating more space than we need.
402 desc.Width = width;
403 desc.Height = height;
404 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400405 nullptr, nullptr, &combinedBufferSize);
406 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400407 SkASSERT(combinedBufferSize);
408
409 // TODO: do this until we have slices of buttery buffers
410 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
411 GrGpuBufferType::kXferCpuToGpu,
412 kDynamic_GrAccessPattern);
413 if (!transferBuffer) {
414 return false;
415 }
416 char* bufferData = (char*)transferBuffer->map();
417
418 int currentWidth = width;
419 int currentHeight = height;
420 int layerHeight = tex->height();
421
422 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
423 if (texels[currentMipLevel].fPixels) {
424 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
425
Jim Van Verthfdd36852020-04-21 16:29:44 -0400426 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400427 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
428
429 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
430
431 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400432 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400433 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
434 src, srcRowBytes, trimRowBytes, currentHeight);
435 }
436 currentWidth = std::max(1, currentWidth / 2);
437 currentHeight = std::max(1, currentHeight / 2);
438 layerHeight = currentHeight;
439 }
440
441 transferBuffer->unmap();
442
443 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
444 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
445 placedFootprints.get(), left, top);
446
447 if (mipLevelCount < (int)desc.MipLevels) {
448 tex->texturePriv().markMipMapsDirty();
449 }
450
451 return true;
452}
453
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400454static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
455 if (!caps.isFormatTexturable(info.fFormat)) {
456 return false;
457 }
458 return true;
459}
460
461static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
462 int sampleCnt) {
463 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
464 return false;
465 }
466 return true;
467}
468
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400469sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
470 GrWrapOwnership,
471 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400472 GrIOType ioType) {
473 GrD3DTextureResourceInfo textureInfo;
474 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
475 return nullptr;
476 }
477
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400478 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400479 return nullptr;
480 }
481
482 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
483 return nullptr;
484 }
485
486 // TODO: support protected context
487 if (tex.isProtected()) {
488 return nullptr;
489 }
490
491 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
492 SkASSERT(state);
493 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
494 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500495}
496
497sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400498 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500499 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400500 GrD3DTextureResourceInfo textureInfo;
501 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
502 return nullptr;
503 }
504
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400505 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400506 return nullptr;
507 }
508
509 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
510 return nullptr;
511 }
512
513 // TODO: support protected context
514 if (tex.isProtected()) {
515 return nullptr;
516 }
517
518 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
519 SkASSERT(state);
520 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
521 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500522}
523
524sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
525 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500526 GrWrapOwnership ownership,
527 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400528 GrD3DTextureResourceInfo textureInfo;
529 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
530 return nullptr;
531 }
532
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400533 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400534 return nullptr;
535 }
536
537 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
538 return nullptr;
539 }
540 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
541 return nullptr;
542 }
543
544 // TODO: support protected context
545 if (tex.isProtected()) {
546 return nullptr;
547 }
548
549 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
550
551 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
552 SkASSERT(state);
553
554 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
555 sampleCnt, cacheable,
556 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500557}
558
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400559sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400560 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
561 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
562 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
563 // creating and owning the MSAA images.
564 if (rt.sampleCnt() > 1) {
565 return nullptr;
566 }
567
568 GrD3DTextureResourceInfo info;
569 if (!rt.getD3DTextureResourceInfo(&info)) {
570 return nullptr;
571 }
572
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400573 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400574 return nullptr;
575 }
576
577 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
578 return nullptr;
579 }
580
581 // TODO: support protected context
582 if (rt.isProtected()) {
583 return nullptr;
584 }
585
586 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
587
588 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
589 this, rt.dimensions(), 1, info, std::move(state));
590
591 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
592 SkASSERT(!rt.stencilBits());
593 if (tgt) {
594 SkASSERT(tgt->canAttemptStencilAttachment());
595 }
596
597 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500598}
599
600sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400601 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400602
603 GrD3DTextureResourceInfo textureInfo;
604 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
605 return nullptr;
606 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400607 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400608 return nullptr;
609 }
610
611 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
612 return nullptr;
613 }
614
615 // TODO: support protected context
616 if (tex.isProtected()) {
617 return nullptr;
618 }
619
620 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
621 if (!sampleCnt) {
622 return nullptr;
623 }
624
625 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
626 SkASSERT(state);
627
628 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
629 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500630}
631
632sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400633 GrAccessPattern accessPattern, const void* data) {
634 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
635 if (data && buffer) {
636 buffer->updateData(data, sizeInBytes);
637 }
638
639 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500640}
641
642GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
643 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400644 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
645 SkASSERT(width >= rt->width());
646 SkASSERT(height >= rt->height());
647
648 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
649
650 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
651 width,
652 height,
653 numStencilSamples,
654 sFmt));
655 fStats.incStencilAttachmentCreates();
656 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500657}
658
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400659bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
660 SkISize dimensions,
661 GrTexturable texturable,
662 GrRenderable renderable,
663 GrMipMapped mipMapped,
664 GrD3DTextureResourceInfo* info,
665 GrProtected isProtected,
666 const BackendTextureData* data) {
667 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
668 if (texturable == GrTexturable::kNo) {
669 SkASSERT(!data && mipMapped == GrMipMapped::kNo);
670 }
671
672 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
673 return false;
674 }
675
676 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
677 return false;
678 }
679
680 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
681 return false;
682 }
683
684 int numMipLevels = 1;
685 if (mipMapped == GrMipMapped::kYes) {
686 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
687 }
688
689 // create the texture
690 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
691 if (renderable == GrRenderable::kYes) {
692 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
693 }
694
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400695 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400696 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
697 resourceDesc.Alignment = 0; // use default alignment
698 resourceDesc.Width = dimensions.fWidth;
699 resourceDesc.Height = dimensions.fHeight;
700 resourceDesc.DepthOrArraySize = 1;
701 resourceDesc.MipLevels = numMipLevels;
702 resourceDesc.Format = dxgiFormat;
703 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400704 // quality levels are only supported for tiled resources so ignore for now
705 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400706 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
707 resourceDesc.Flags = usageFlags;
708
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400709 D3D12_RESOURCE_STATES initialState =
710 (renderable == GrRenderable::kYes) && !data ? D3D12_RESOURCE_STATE_RENDER_TARGET :
711 D3D12_RESOURCE_STATE_COPY_DEST;
712 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
713 isProtected, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400714 SkDebugf("Failed to init texture resource info\n");
715 return false;
716 }
717
718 if (!data) {
719 return true;
720 }
721
722 // TODO: upload the data
723
724 return true;
725}
726
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500727GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400728 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400729 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400730 GrMipMapped mipMapped,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400731 GrProtected isProtected,
732 const BackendTextureData* data) {
733 this->handleDirtyContext();
734
735 const GrD3DCaps& caps = this->d3dCaps();
736
737 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
738 return {};
739 }
740
741 DXGI_FORMAT dxgiFormat;
742 if (!format.asDxgiFormat(&dxgiFormat)) {
743 return {};
744 }
745
746 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
747 if (!caps.isFormatTexturable(dxgiFormat)) {
748 return {};
749 }
750
751 GrD3DTextureResourceInfo info;
752 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
753 renderable, mipMapped,
754 &info, isProtected, data)) {
755 return {};
756 }
757
758 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500759}
760
761GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400762 const GrBackendFormat& format,
763 GrMipMapped mipMapped,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400764 GrProtected isProtected,
765 const BackendTextureData* data) {
766 this->handleDirtyContext();
767
768 const GrD3DCaps& caps = this->d3dCaps();
769
770 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
771 return {};
772 }
773
774 DXGI_FORMAT dxgiFormat;
775 if (!format.asDxgiFormat(&dxgiFormat)) {
776 return {};
777 }
778
779 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
780 if (!caps.isFormatTexturable(dxgiFormat)) {
781 return {};
782 }
783
784 GrD3DTextureResourceInfo info;
785 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
786 GrRenderable::kNo, mipMapped,
787 &info, isProtected, data)) {
788 return {};
789 }
790
791 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500792}
793
794void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400795 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
796 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500797}
798
Robert Phillips979b2232020-02-20 10:47:29 -0500799bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
800 return false;
801}
802
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500803#if GR_TEST_UTILS
804bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400805 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
806
807 GrD3DTextureResourceInfo info;
808 if (!tex.getD3DTextureResourceInfo(&info)) {
809 return false;
810 }
811 ID3D12Resource* textureResource = info.fResource.get();
812 if (!textureResource) {
813 return false;
814 }
815 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500816}
817
818GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400819 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400820 this->handleDirtyContext();
821
822 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400823 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400824 }
825
826 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
827
828 GrD3DTextureResourceInfo info;
829 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
830 GrRenderable::kYes, GrMipMapped::kNo,
831 &info, GrProtected::kNo, nullptr)) {
832 return {};
833 }
834
835 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500836}
837
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400838void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
839 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
840
841 GrD3DTextureResourceInfo info;
842 if (rt.getD3DTextureResourceInfo(&info)) {
843 this->testingOnly_flushGpuAndSync();
844 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
845 // is deleted.
846 }
847}
848
849void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -0400850 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400851}
Jim Van Verthc632aa62020-04-17 16:58:20 -0400852
Jim Van Verth9b5e16c2020-04-20 10:45:52 -0400853void GrD3DGpu::testingOnly_startCapture() {
854 if (fGraphicsAnalysis) {
855 fGraphicsAnalysis->BeginCapture();
856 }
857}
858
859void GrD3DGpu::testingOnly_endCapture() {
860 if (fGraphicsAnalysis) {
861 fGraphicsAnalysis->EndCapture();
862 }
863}
864#endif
865
Jim Van Verthc632aa62020-04-17 16:58:20 -0400866///////////////////////////////////////////////////////////////////////////////
867
868void GrD3DGpu::addResourceBarriers(const GrManagedResource* resource,
869 int numBarriers,
870 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
871 SkASSERT(fCurrentDirectCommandList);
872 SkASSERT(resource);
873
874 fCurrentDirectCommandList->resourceBarrier(resource, numBarriers, barriers);
875}
876
877bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
878 if (syncCpu) {
879 return this->submitDirectCommandList(SyncQueue::kForce);
880 } else {
881 return this->submitDirectCommandList(SyncQueue::kSkip);
882 }
883}