blob: 2c2c2b42cc58c9740046a316e9cd0617450d42da [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
Jim Van Verthc12aad92020-04-24 16:19:01 -0400275 GrD3DTextureResource* texResource = nullptr;
276 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
277 if (rt) {
278 texResource = rt;
279 } else {
280 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
281 }
282
283 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400284 return false;
285 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400286
Jim Van Verthba7f2292020-04-21 08:56:47 -0400287 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400288 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400289 SkASSERT(srcLocation.pResource);
290 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
291 srcLocation.SubresourceIndex = 0;
292
293 D3D12_BOX srcBox = {};
294 srcBox.left = left;
295 srcBox.top = top;
296 srcBox.right = left + width;
297 srcBox.bottom = top + height;
298 srcBox.front = 0;
299 srcBox.back = 1;
300
301 // Set up dst location and create transfer buffer
302 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
303 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400304 UINT64 transferTotalBytes;
305 const UINT64 baseOffset = 0;
306 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
307 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400308 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400309 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400310 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Jim Van Verthc12aad92020-04-24 16:19:01 -0400311 if (this->d3dCaps().bytesPerPixel(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400312 return false;
313 }
314 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400315
316 // TODO: implement some way of reusing buffers instead of making a new one every time.
317 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
318 GrGpuBufferType::kXferGpuToCpu,
319 kDynamic_GrAccessPattern);
320 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
321 dstLocation.pResource = d3dBuf->d3dResource();
322
323 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400324 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400325
326 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
Jim Van Verthc12aad92020-04-24 16:19:01 -0400327 texResource->resource(), &srcLocation, &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400328 this->submitDirectCommandList(SyncQueue::kForce);
329
330 const void* mappedMemory = transferBuffer->map();
331
332 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400333 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400334
335 transferBuffer->unmap();
336
337 return true;
338}
339
340bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
341 GrColorType surfaceColorType, GrColorType srcColorType,
342 const GrMipLevel texels[], int mipLevelCount,
343 bool prepForTexSampling) {
344 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
345 if (!d3dTex) {
346 return false;
347 }
348
349 // Make sure we have at least the base level
350 if (!mipLevelCount || !texels[0].fPixels) {
351 return false;
352 }
353
354 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
355 bool success = false;
356
357 // Need to change the resource state to COPY_DEST in order to upload to it
358 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
359
360 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
361 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
362 mipLevelCount);
363
364 if (prepForTexSampling) {
365 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
366 }
367
368 return success;
369}
370
371bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
372 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
373 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
374 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
375 SkASSERT(1 == mipLevelCount ||
376 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
377
378 // We assume that if the texture has mip levels, we either upload to all the levels or just the
379 // first.
380 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
381
382 if (width == 0 || height == 0) {
383 return false;
384 }
385
386 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
387 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
388
389 ID3D12Resource* d3dResource = tex->d3dResource();
390 SkASSERT(d3dResource);
391 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
392 // Either upload only the first miplevel or all miplevels
393 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
394
395 if (1 == mipLevelCount && !texels[0].fPixels) {
396 return true; // no data to upload
397 }
398
399 for (int i = 0; i < mipLevelCount; ++i) {
400 // We do not allow any gaps in the mip data
401 if (!texels[i].fPixels) {
402 return false;
403 }
404 }
405
406 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400407 UINT64 combinedBufferSize;
408 // We reset the width and height in the description to match our subrectangle size
409 // so we don't end up allocating more space than we need.
410 desc.Width = width;
411 desc.Height = height;
412 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400413 nullptr, nullptr, &combinedBufferSize);
414 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400415 SkASSERT(combinedBufferSize);
416
417 // TODO: do this until we have slices of buttery buffers
418 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize,
419 GrGpuBufferType::kXferCpuToGpu,
420 kDynamic_GrAccessPattern);
421 if (!transferBuffer) {
422 return false;
423 }
424 char* bufferData = (char*)transferBuffer->map();
425
426 int currentWidth = width;
427 int currentHeight = height;
428 int layerHeight = tex->height();
429
430 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
431 if (texels[currentMipLevel].fPixels) {
432 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
433
Jim Van Verthfdd36852020-04-21 16:29:44 -0400434 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400435 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
436
437 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
438
439 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400440 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400441 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
442 src, srcRowBytes, trimRowBytes, currentHeight);
443 }
444 currentWidth = std::max(1, currentWidth / 2);
445 currentHeight = std::max(1, currentHeight / 2);
446 layerHeight = currentHeight;
447 }
448
449 transferBuffer->unmap();
450
451 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get());
452 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
453 placedFootprints.get(), left, top);
454
455 if (mipLevelCount < (int)desc.MipLevels) {
456 tex->texturePriv().markMipMapsDirty();
457 }
458
459 return true;
460}
461
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400462static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
463 if (!caps.isFormatTexturable(info.fFormat)) {
464 return false;
465 }
466 return true;
467}
468
469static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
470 int sampleCnt) {
471 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
472 return false;
473 }
474 return true;
475}
476
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400477sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
478 GrWrapOwnership,
479 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400480 GrIOType ioType) {
481 GrD3DTextureResourceInfo textureInfo;
482 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
483 return nullptr;
484 }
485
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400486 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400487 return nullptr;
488 }
489
490 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
491 return nullptr;
492 }
493
494 // TODO: support protected context
495 if (tex.isProtected()) {
496 return nullptr;
497 }
498
499 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
500 SkASSERT(state);
501 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
502 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500503}
504
505sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400506 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500507 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400508 GrD3DTextureResourceInfo textureInfo;
509 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
510 return nullptr;
511 }
512
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400513 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400514 return nullptr;
515 }
516
517 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
518 return nullptr;
519 }
520
521 // TODO: support protected context
522 if (tex.isProtected()) {
523 return nullptr;
524 }
525
526 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
527 SkASSERT(state);
528 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
529 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500530}
531
532sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
533 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500534 GrWrapOwnership ownership,
535 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400536 GrD3DTextureResourceInfo textureInfo;
537 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
538 return nullptr;
539 }
540
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400541 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400542 return nullptr;
543 }
544
545 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
546 return nullptr;
547 }
548 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
549 return nullptr;
550 }
551
552 // TODO: support protected context
553 if (tex.isProtected()) {
554 return nullptr;
555 }
556
557 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
558
559 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
560 SkASSERT(state);
561
562 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
563 sampleCnt, cacheable,
564 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500565}
566
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400567sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400568 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
569 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
570 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
571 // creating and owning the MSAA images.
572 if (rt.sampleCnt() > 1) {
573 return nullptr;
574 }
575
576 GrD3DTextureResourceInfo info;
577 if (!rt.getD3DTextureResourceInfo(&info)) {
578 return nullptr;
579 }
580
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400581 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400582 return nullptr;
583 }
584
585 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
586 return nullptr;
587 }
588
589 // TODO: support protected context
590 if (rt.isProtected()) {
591 return nullptr;
592 }
593
594 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
595
596 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
597 this, rt.dimensions(), 1, info, std::move(state));
598
599 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
600 SkASSERT(!rt.stencilBits());
601 if (tgt) {
602 SkASSERT(tgt->canAttemptStencilAttachment());
603 }
604
605 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500606}
607
608sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400609 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400610
611 GrD3DTextureResourceInfo textureInfo;
612 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
613 return nullptr;
614 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400615 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400616 return nullptr;
617 }
618
619 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
620 return nullptr;
621 }
622
623 // TODO: support protected context
624 if (tex.isProtected()) {
625 return nullptr;
626 }
627
628 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
629 if (!sampleCnt) {
630 return nullptr;
631 }
632
633 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
634 SkASSERT(state);
635
636 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
637 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500638}
639
640sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400641 GrAccessPattern accessPattern, const void* data) {
642 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
643 if (data && buffer) {
644 buffer->updateData(data, sizeInBytes);
645 }
646
647 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500648}
649
650GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
651 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400652 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
653 SkASSERT(width >= rt->width());
654 SkASSERT(height >= rt->height());
655
656 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
657
658 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
659 width,
660 height,
661 numStencilSamples,
662 sFmt));
663 fStats.incStencilAttachmentCreates();
664 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500665}
666
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400667bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
668 SkISize dimensions,
669 GrTexturable texturable,
670 GrRenderable renderable,
671 GrMipMapped mipMapped,
672 GrD3DTextureResourceInfo* info,
673 GrProtected isProtected,
674 const BackendTextureData* data) {
675 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
676 if (texturable == GrTexturable::kNo) {
677 SkASSERT(!data && mipMapped == GrMipMapped::kNo);
678 }
679
680 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
681 return false;
682 }
683
684 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
685 return false;
686 }
687
688 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
689 return false;
690 }
691
692 int numMipLevels = 1;
693 if (mipMapped == GrMipMapped::kYes) {
694 numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
695 }
696
697 // create the texture
698 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
699 if (renderable == GrRenderable::kYes) {
700 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
701 }
702
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400703 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400704 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
705 resourceDesc.Alignment = 0; // use default alignment
706 resourceDesc.Width = dimensions.fWidth;
707 resourceDesc.Height = dimensions.fHeight;
708 resourceDesc.DepthOrArraySize = 1;
709 resourceDesc.MipLevels = numMipLevels;
710 resourceDesc.Format = dxgiFormat;
711 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400712 // quality levels are only supported for tiled resources so ignore for now
713 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400714 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
715 resourceDesc.Flags = usageFlags;
716
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400717 D3D12_RESOURCE_STATES initialState =
718 (renderable == GrRenderable::kYes) && !data ? D3D12_RESOURCE_STATE_RENDER_TARGET :
719 D3D12_RESOURCE_STATE_COPY_DEST;
720 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
721 isProtected, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400722 SkDebugf("Failed to init texture resource info\n");
723 return false;
724 }
725
726 if (!data) {
727 return true;
728 }
729
730 // TODO: upload the data
731
732 return true;
733}
734
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500735GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400736 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400737 GrRenderable renderable,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400738 GrMipMapped mipMapped,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400739 GrProtected isProtected,
740 const BackendTextureData* data) {
741 this->handleDirtyContext();
742
743 const GrD3DCaps& caps = this->d3dCaps();
744
745 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
746 return {};
747 }
748
749 DXGI_FORMAT dxgiFormat;
750 if (!format.asDxgiFormat(&dxgiFormat)) {
751 return {};
752 }
753
754 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
755 if (!caps.isFormatTexturable(dxgiFormat)) {
756 return {};
757 }
758
759 GrD3DTextureResourceInfo info;
760 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
761 renderable, mipMapped,
762 &info, isProtected, data)) {
763 return {};
764 }
765
766 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500767}
768
769GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400770 const GrBackendFormat& format,
771 GrMipMapped mipMapped,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400772 GrProtected isProtected,
773 const BackendTextureData* data) {
774 this->handleDirtyContext();
775
776 const GrD3DCaps& caps = this->d3dCaps();
777
778 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
779 return {};
780 }
781
782 DXGI_FORMAT dxgiFormat;
783 if (!format.asDxgiFormat(&dxgiFormat)) {
784 return {};
785 }
786
787 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
788 if (!caps.isFormatTexturable(dxgiFormat)) {
789 return {};
790 }
791
792 GrD3DTextureResourceInfo info;
793 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
794 GrRenderable::kNo, mipMapped,
795 &info, isProtected, data)) {
796 return {};
797 }
798
799 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500800}
801
802void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400803 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
804 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500805}
806
Robert Phillips979b2232020-02-20 10:47:29 -0500807bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
808 return false;
809}
810
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500811#if GR_TEST_UTILS
812bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400813 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
814
815 GrD3DTextureResourceInfo info;
816 if (!tex.getD3DTextureResourceInfo(&info)) {
817 return false;
818 }
819 ID3D12Resource* textureResource = info.fResource.get();
820 if (!textureResource) {
821 return false;
822 }
823 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500824}
825
826GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400827 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400828 this->handleDirtyContext();
829
830 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400831 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400832 }
833
834 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
835
836 GrD3DTextureResourceInfo info;
837 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
838 GrRenderable::kYes, GrMipMapped::kNo,
839 &info, GrProtected::kNo, nullptr)) {
840 return {};
841 }
842
843 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500844}
845
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400846void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
847 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
848
849 GrD3DTextureResourceInfo info;
850 if (rt.getD3DTextureResourceInfo(&info)) {
851 this->testingOnly_flushGpuAndSync();
852 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
853 // is deleted.
854 }
855}
856
857void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -0400858 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400859}
Jim Van Verthc632aa62020-04-17 16:58:20 -0400860
Jim Van Verth9b5e16c2020-04-20 10:45:52 -0400861void GrD3DGpu::testingOnly_startCapture() {
862 if (fGraphicsAnalysis) {
863 fGraphicsAnalysis->BeginCapture();
864 }
865}
866
867void GrD3DGpu::testingOnly_endCapture() {
868 if (fGraphicsAnalysis) {
869 fGraphicsAnalysis->EndCapture();
870 }
871}
872#endif
873
Jim Van Verthc632aa62020-04-17 16:58:20 -0400874///////////////////////////////////////////////////////////////////////////////
875
Greg Daniela5a6b322020-04-23 12:52:27 -0400876void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -0400877 int numBarriers,
878 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
879 SkASSERT(fCurrentDirectCommandList);
880 SkASSERT(resource);
881
Greg Daniela5a6b322020-04-23 12:52:27 -0400882 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400883}
884
885bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
886 if (syncCpu) {
887 return this->submitDirectCommandList(SyncQueue::kForce);
888 } else {
889 return this->submitDirectCommandList(SyncQueue::kSkip);
890 }
891}