blob: f9f02028e5666b16a9b070f7115a2bccc0141a0a [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"
Mike Reed13711eb2020-07-14 17:16:32 -040013#include "src/core/SkMipmap.h"
Jim Van Verth43a6e172020-06-23 11:59:08 -040014#include "src/gpu/GrBackendUtils.h"
Jim Van Verthc632aa62020-04-17 16:58:20 -040015#include "src/gpu/GrDataUtils.h"
16#include "src/gpu/GrTexturePriv.h"
Jim Van Verthd6ad4802020-04-03 14:59:20 -040017#include "src/gpu/d3d/GrD3DBuffer.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050018#include "src/gpu/d3d/GrD3DCaps.h"
19#include "src/gpu/d3d/GrD3DOpsRenderPass.h"
Jim Van Verthc1a67b52020-06-25 13:10:29 -040020#include "src/gpu/d3d/GrD3DSemaphore.h"
Jim Van Verth4f51f472020-04-13 11:02:21 -040021#include "src/gpu/d3d/GrD3DStencilAttachment.h"
Jim Van Verthaa90dad2020-03-30 15:00:39 -040022#include "src/gpu/d3d/GrD3DTexture.h"
23#include "src/gpu/d3d/GrD3DTextureRenderTarget.h"
24#include "src/gpu/d3d/GrD3DUtil.h"
Greg Daniel5fc5c812020-04-23 10:30:23 -040025#include "src/sksl/SkSLCompiler.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050026
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040027#if GR_TEST_UTILS
28#include <DXProgrammableCapture.h>
29#endif
30
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050031sk_sp<GrGpu> GrD3DGpu::Make(const GrD3DBackendContext& backendContext,
Adlai Holler3d0359a2020-07-09 15:35:55 -040032 const GrContextOptions& contextOptions, GrDirectContext* direct) {
33 return sk_sp<GrGpu>(new GrD3DGpu(direct, contextOptions, backendContext));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050034}
35
Greg Daniel83ed2132020-03-24 13:15:33 -040036// This constant determines how many OutstandingCommandLists are allocated together as a block in
37// the deque. As such it needs to balance allocating too much memory vs. incurring
38// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
39// command lists we expect to see.
40static const int kDefaultOutstandingAllocCnt = 8;
41
Adlai Holler3d0359a2020-07-09 15:35:55 -040042GrD3DGpu::GrD3DGpu(GrDirectContext* direct, const GrContextOptions& contextOptions,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050043 const GrD3DBackendContext& backendContext)
Adlai Holler3d0359a2020-07-09 15:35:55 -040044 : INHERITED(direct)
Jim Van Verth03b8ab22020-02-24 11:36:15 -050045 , fDevice(backendContext.fDevice)
Greg Daniel02c45902020-03-09 10:58:09 -040046
47 , fQueue(backendContext.fQueue)
Greg Daniel83ed2132020-03-24 13:15:33 -040048 , fResourceProvider(this)
Greg Danielcffb0622020-07-16 13:19:17 -040049 , fStagingBufferManager(this)
Greg Daniel5fc5c812020-04-23 10:30:23 -040050 , fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt)
51 , fCompiler(new SkSL::Compiler()) {
Jim Van Verth8ec13302020-02-26 12:59:56 -050052 fCaps.reset(new GrD3DCaps(contextOptions,
Jim Van Verth9aa9a682020-04-01 10:13:48 -040053 backendContext.fAdapter.get(),
54 backendContext.fDevice.get()));
Greg Daniel85da3362020-03-09 15:18:35 -040055
56 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
Greg Daniele52c9782020-03-23 14:18:37 -040057 SkASSERT(fCurrentDirectCommandList);
Greg Daniel83ed2132020-03-24 13:15:33 -040058
59 SkASSERT(fCurrentFenceValue == 0);
Jim Van Verthe3810362020-07-01 10:12:11 -040060 GR_D3D_CALL_ERRCHECK(fDevice->CreateFence(fCurrentFenceValue, D3D12_FENCE_FLAG_NONE,
61 IID_PPV_ARGS(&fFence)));
Jim Van Verth9b5e16c2020-04-20 10:45:52 -040062
63#if GR_TEST_UTILS
64 HRESULT getAnalysis = DXGIGetDebugInterface1(0, IID_PPV_ARGS(&fGraphicsAnalysis));
65 if (FAILED(getAnalysis)) {
66 fGraphicsAnalysis = nullptr;
67 }
68#endif
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050069}
70
Greg Daniel83ed2132020-03-24 13:15:33 -040071GrD3DGpu::~GrD3DGpu() {
72 this->destroyResources();
73}
74
75void GrD3DGpu::destroyResources() {
76 if (fCurrentDirectCommandList) {
77 fCurrentDirectCommandList->close();
Jim Van Verthba7f2292020-04-21 08:56:47 -040078 fCurrentDirectCommandList->reset();
Greg Daniel83ed2132020-03-24 13:15:33 -040079 }
80
81 // We need to make sure everything has finished on the queue.
Jim Van Verth3b0d7d12020-07-06 11:52:42 -040082 this->waitForQueueCompletion();
Greg Daniel83ed2132020-03-24 13:15:33 -040083
84 SkDEBUGCODE(uint64_t fenceValue = fFence->GetCompletedValue();)
85
86 // We used a placement new for each object in fOutstandingCommandLists, so we're responsible
87 // for calling the destructor on each of them as well.
88 while (!fOutstandingCommandLists.empty()) {
Jim Van Verthf43da142020-06-09 16:34:43 -040089 OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel83ed2132020-03-24 13:15:33 -040090 SkASSERT(list->fFenceValue <= fenceValue);
91 // No reason to recycle the command lists since we are destroying all resources anyways.
92 list->~OutstandingCommandList();
Jim Van Verthf43da142020-06-09 16:34:43 -040093 fOutstandingCommandLists.pop_front();
Greg Daniel83ed2132020-03-24 13:15:33 -040094 }
Jim Van Verthf2788862020-06-03 17:33:12 -040095
Greg Danielcffb0622020-07-16 13:19:17 -040096 fStagingBufferManager.reset();
97
Jim Van Verthf2788862020-06-03 17:33:12 -040098 fResourceProvider.destroyResources();
Greg Daniel83ed2132020-03-24 13:15:33 -040099}
Greg Daniel31a7b072020-02-26 15:31:49 -0500100
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500101GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
Robert Phillips96f22372020-05-20 12:31:18 -0400102 GrRenderTarget* rt, GrStencilAttachment*,
103 GrSurfaceOrigin origin, const SkIRect& bounds,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500104 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -0500105 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500106 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -0500107 if (!fCachedOpsRenderPass) {
108 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
109 }
110
111 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
112 return nullptr;
113 }
114 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500115}
116
Jim Van Verthc632aa62020-04-17 16:58:20 -0400117bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) {
Greg Daniel83ed2132020-03-24 13:15:33 -0400118 SkASSERT(fCurrentDirectCommandList);
119
Jim Van Verth3eadce22020-06-01 11:34:49 -0400120 fResourceProvider.prepForSubmit();
121
Jim Van Verthc632aa62020-04-17 16:58:20 -0400122 GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get());
123 if (result == GrD3DDirectCommandList::SubmitResult::kFailure) {
124 return false;
125 } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) {
126 if (sync == SyncQueue::kForce) {
Jim Van Verth3b0d7d12020-07-06 11:52:42 -0400127 this->waitForQueueCompletion();
Jim Van Verth682a2f42020-05-13 16:54:09 -0400128 this->checkForFinishedCommandLists();
Jim Van Verthc632aa62020-04-17 16:58:20 -0400129 }
130 return true;
131 }
Greg Daniel83ed2132020-03-24 13:15:33 -0400132
Greg Daniela581a8b2020-06-19 15:22:18 -0400133 // We just submitted the command list so make sure all GrD3DPipelineState's mark their cached
134 // uniform data as dirty.
135 fResourceProvider.markPipelineStateUniformsDirty();
136
Jim Van Verth1e6460d2020-06-30 15:47:52 -0400137 GrFence fence = this->insertFence();
Greg Daniel83ed2132020-03-24 13:15:33 -0400138 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
Jim Van Verth1e6460d2020-06-30 15:47:52 -0400139 std::move(fCurrentDirectCommandList), fence);
Greg Daniel83ed2132020-03-24 13:15:33 -0400140
Jim Van Verthc632aa62020-04-17 16:58:20 -0400141 if (sync == SyncQueue::kForce) {
Jim Van Verth3b0d7d12020-07-06 11:52:42 -0400142 this->waitForQueueCompletion();
Jim Van Verthc632aa62020-04-17 16:58:20 -0400143 }
144
Greg Daniel83ed2132020-03-24 13:15:33 -0400145 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
146
147 // This should be done after we have a new command list in case the freeing of any resources
148 // held by a finished command list causes us send a new command to the gpu (like changing the
149 // resource state.
150 this->checkForFinishedCommandLists();
151
152 SkASSERT(fCurrentDirectCommandList);
Jim Van Verthc632aa62020-04-17 16:58:20 -0400153 return true;
Greg Daniel83ed2132020-03-24 13:15:33 -0400154}
155
156void GrD3DGpu::checkForFinishedCommandLists() {
157 uint64_t currentFenceValue = fFence->GetCompletedValue();
158
159 // Iterate over all the outstanding command lists to see if any have finished. The commands
160 // lists are in order from oldest to newest, so we start at the front to check if their fence
161 // value is less than the last signaled value. If so we pop it off and move onto the next.
162 // Repeat till we find a command list that has not finished yet (and all others afterwards are
163 // also guaranteed to not have finished).
Jim Van Verthdd3b4012020-06-30 15:28:17 -0400164 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
165 while (front && front->fFenceValue <= currentFenceValue) {
166 std::unique_ptr<GrD3DDirectCommandList> currList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400167 // Since we used placement new we are responsible for calling the destructor manually.
168 front->~OutstandingCommandList();
169 fOutstandingCommandLists.pop_front();
Jim Van Verthdd3b4012020-06-30 15:28:17 -0400170 fResourceProvider.recycleDirectCommandList(std::move(currList));
171 front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel83ed2132020-03-24 13:15:33 -0400172 }
173}
174
Jim Van Verth3b0d7d12020-07-06 11:52:42 -0400175void GrD3DGpu::waitForQueueCompletion() {
176 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
177 HANDLE fenceEvent;
178 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
179 SkASSERT(fenceEvent);
180 GR_D3D_CALL_ERRCHECK(fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent));
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));
Jim Van Verth43a6e172020-06-23 11:59:08 -0400198 this->addFinishedCallback(std::move(finishedCallback));
199}
200
201void GrD3DGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) {
202 SkASSERT(finishedCallback);
Greg Danield4928d02020-06-19 11:13:26 -0400203 // Besides the current command list, we also add the finishedCallback to the newest outstanding
204 // command list. Our contract for calling the proc is that all previous submitted command lists
205 // have finished when we call it. However, if our current command list has no work when it is
206 // flushed it will drop its ref to the callback immediately. But the previous work may not have
207 // finished. It is safe to only add the proc to the newest outstanding commandlist cause that
208 // must finish after all previously submitted command lists.
209 OutstandingCommandList* back = (OutstandingCommandList*)fOutstandingCommandLists.back();
210 if (back) {
211 back->fCommandList->addFinishedCallback(finishedCallback);
212 }
213 fCurrentDirectCommandList->addFinishedCallback(std::move(finishedCallback));
214}
215
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500216void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
217 // TODO
218}
219
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400220sk_sp<GrD3DTexture> GrD3DGpu::createD3DTexture(SkISize dimensions,
221 DXGI_FORMAT dxgiFormat,
222 GrRenderable renderable,
223 int renderTargetSampleCnt,
224 SkBudgeted budgeted,
225 GrProtected isProtected,
226 int mipLevelCount,
227 GrMipMapsStatus mipMapsStatus) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400228 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400229 if (renderable == GrRenderable::kYes) {
230 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
231 }
232
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400233 // This desc refers to a texture that will be read by the client. Thus even if msaa is
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400234 // 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
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400253 if (renderable == GrRenderable::kYes) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400254 return GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400255 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
256 mipMapsStatus);
257 } else {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400258 return GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
259 mipMapsStatus);
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400260 }
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400261}
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400262
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400263sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
264 const GrBackendFormat& format,
265 GrRenderable renderable,
266 int renderTargetSampleCnt,
267 SkBudgeted budgeted,
268 GrProtected isProtected,
269 int mipLevelCount,
270 uint32_t levelClearMask) {
271 DXGI_FORMAT dxgiFormat;
272 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
273 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
274
275 GrMipMapsStatus mipMapsStatus = mipLevelCount > 1 ? GrMipMapsStatus::kDirty
276 : GrMipMapsStatus::kNotAllocated;
277
278 sk_sp<GrD3DTexture> tex = this->createD3DTexture(dimensions, dxgiFormat, renderable,
279 renderTargetSampleCnt, budgeted, isProtected,
280 mipLevelCount, mipMapsStatus);
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400281 if (!tex) {
282 return nullptr;
283 }
284
285 if (levelClearMask) {
286 // TODO
287 }
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400288
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400289 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500290}
291
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400292static void copy_compressed_data(char* mapPtr, DXGI_FORMAT dxgiFormat,
293 D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
294 UINT* numRows, UINT64* rowSizeInBytes,
295 const void* compressedData, int numMipLevels) {
296 SkASSERT(compressedData && numMipLevels);
297 SkASSERT(GrDxgiFormatIsCompressed(dxgiFormat));
298 SkASSERT(mapPtr);
299
300 const char* src = static_cast<const char*>(compressedData);
301 for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
302 // copy data into the buffer, skipping any trailing bytes
303 char* dst = mapPtr + placedFootprints[currentMipLevel].Offset;
304 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
305 src, rowSizeInBytes[currentMipLevel], rowSizeInBytes[currentMipLevel],
306 numRows[currentMipLevel]);
307 src += numRows[currentMipLevel] * rowSizeInBytes[currentMipLevel];
308 }
309}
310
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500311sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
312 const GrBackendFormat& format,
313 SkBudgeted budgeted,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400314 GrMipmapped mipMapped,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500315 GrProtected isProtected,
316 const void* data, size_t dataSize) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400317 DXGI_FORMAT dxgiFormat;
318 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
319 SkASSERT(GrDxgiFormatIsCompressed(dxgiFormat));
320
321 SkDEBUGCODE(SkImage::CompressionType compression = GrBackendFormatToCompressionType(format));
322 SkASSERT(dataSize == SkCompressedFormatDataSize(compression, dimensions,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400323 mipMapped == GrMipmapped::kYes));
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400324
325 int mipLevelCount = 1;
Brian Salomon7e67dca2020-07-21 09:27:25 -0400326 if (mipMapped == GrMipmapped::kYes) {
Mike Reed13711eb2020-07-14 17:16:32 -0400327 mipLevelCount = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400328 }
329 GrMipMapsStatus mipMapsStatus = mipLevelCount > 1 ? GrMipMapsStatus::kValid
330 : GrMipMapsStatus::kNotAllocated;
331
332 sk_sp<GrD3DTexture> d3dTex = this->createD3DTexture(dimensions, dxgiFormat, GrRenderable::kNo,
333 1, budgeted, isProtected,
334 mipLevelCount, mipMapsStatus);
335 if (!d3dTex) {
336 return nullptr;
337 }
338
339 ID3D12Resource* d3dResource = d3dTex->d3dResource();
340 SkASSERT(d3dResource);
341 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
342 // Either upload only the first miplevel or all miplevels
343 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
344
345 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
346 SkAutoTMalloc<UINT> numRows(mipLevelCount);
347 SkAutoTMalloc<UINT64> rowSizeInBytes(mipLevelCount);
348 UINT64 combinedBufferSize;
349 // We reset the width and height in the description to match our subrectangle size
350 // so we don't end up allocating more space than we need.
351 desc.Width = dimensions.width();
352 desc.Height = dimensions.height();
353 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
354 numRows.get(), rowSizeInBytes.get(), &combinedBufferSize);
355 SkASSERT(combinedBufferSize);
356
Greg Danielcffb0622020-07-16 13:19:17 -0400357 GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
358 combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
359 if (!slice.fBuffer) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400360 return false;
361 }
Greg Danielcffb0622020-07-16 13:19:17 -0400362
363 char* bufferData = (char*)slice.fOffsetMapPtr;
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400364
365 copy_compressed_data(bufferData, desc.Format, placedFootprints.get(), numRows.get(),
366 rowSizeInBytes.get(), data, mipLevelCount);
367
Greg Danielcffb0622020-07-16 13:19:17 -0400368 // Update the offsets in the footprints to be relative to the slice's offset
369 for (int i = 0; i < mipLevelCount; ++i) {
370 placedFootprints[i].Offset += slice.fOffset;
371 }
372
373 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer);
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400374 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, d3dTex.get(), mipLevelCount,
375 placedFootprints.get(), 0, 0);
376
377 return std::move(d3dTex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500378}
379
Jim Van Verth9145f782020-04-28 12:01:12 -0400380static int get_surface_sample_cnt(GrSurface* surf) {
381 if (const GrRenderTarget* rt = surf->asRenderTarget()) {
382 return rt->numSamples();
383 }
384 return 0;
385}
386
387bool GrD3DGpu::onCopySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
388 const SkIPoint& dstPoint) {
389
390 if (src->isProtected() && !dst->isProtected()) {
391 SkDebugf("Can't copy from protected memory to non-protected");
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400392 return false;
393 }
Jim Van Verth9145f782020-04-28 12:01:12 -0400394
395 int dstSampleCnt = get_surface_sample_cnt(dst);
396 int srcSampleCnt = get_surface_sample_cnt(src);
397
398 GrD3DTextureResource* dstTexResource;
399 GrD3DTextureResource* srcTexResource;
400 GrRenderTarget* dstRT = dst->asRenderTarget();
401 if (dstRT) {
402 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(dstRT);
403 dstTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
404 } else {
405 SkASSERT(dst->asTexture());
406 dstTexResource = static_cast<GrD3DTexture*>(dst->asTexture());
407 }
408 GrRenderTarget* srcRT = src->asRenderTarget();
409 if (srcRT) {
410 GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(srcRT);
411 srcTexResource = d3dRT->numSamples() > 1 ? d3dRT->msaaTextureResource() : d3dRT;
412 } else {
413 SkASSERT(src->asTexture());
414 srcTexResource = static_cast<GrD3DTexture*>(src->asTexture());
415 }
416
417 DXGI_FORMAT dstFormat = dstTexResource->dxgiFormat();
418 DXGI_FORMAT srcFormat = srcTexResource->dxgiFormat();
419
420 if (this->d3dCaps().canCopyAsResolve(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
421 this->copySurfaceAsResolve(dst, src, srcRect, dstPoint);
422 return true;
423 }
424
425 if (this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt)) {
426 this->copySurfaceAsCopyTexture(dst, src, dstTexResource, srcTexResource, srcRect, dstPoint);
427 return true;
428 }
429
430 return false;
431}
432
433void GrD3DGpu::copySurfaceAsCopyTexture(GrSurface* dst, GrSurface* src,
434 GrD3DTextureResource* dstResource,
435 GrD3DTextureResource* srcResource,
436 const SkIRect& srcRect, const SkIPoint& dstPoint) {
437#ifdef SK_DEBUG
438 int dstSampleCnt = get_surface_sample_cnt(dst);
439 int srcSampleCnt = get_surface_sample_cnt(src);
440 DXGI_FORMAT dstFormat = dstResource->dxgiFormat();
441 DXGI_FORMAT srcFormat;
442 SkAssertResult(dst->backendFormat().asDxgiFormat(&srcFormat));
443 SkASSERT(this->d3dCaps().canCopyTexture(dstFormat, dstSampleCnt, srcFormat, srcSampleCnt));
444#endif
445 if (src->isProtected() && !dst->isProtected()) {
446 SkDebugf("Can't copy from protected memory to non-protected");
447 return;
448 }
449
450 dstResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
451 srcResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
452
453 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
454 dstLocation.pResource = dstResource->d3dResource();
455 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
456 dstLocation.SubresourceIndex = 0;
457
458 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
459 srcLocation.pResource = srcResource->d3dResource();
460 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
461 srcLocation.SubresourceIndex = 0;
462
463 D3D12_BOX srcBox = {};
464 srcBox.left = srcRect.fLeft;
465 srcBox.top = srcRect.fTop;
466 srcBox.right = srcRect.fRight;
467 srcBox.bottom = srcRect.fBottom;
468 srcBox.front = 0;
469 srcBox.back = 1;
470 // TODO: use copyResource if copying full resource and sizes match
471 fCurrentDirectCommandList->copyTextureRegion(dstResource->resource(),
472 &dstLocation,
473 dstPoint.fX, dstPoint.fY,
474 srcResource->resource(),
475 &srcLocation,
476 &srcBox);
477
478 SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
479 srcRect.width(), srcRect.height());
480 // The rect is already in device space so we pass in kTopLeft so no flip is done.
481 this->didWriteToSurface(dst, kTopLeft_GrSurfaceOrigin, &dstRect);
482}
483
484void GrD3DGpu::copySurfaceAsResolve(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
485 const SkIPoint& dstPoint) {
Jim Van Verth275f4192020-07-07 15:36:41 -0400486 GrD3DRenderTarget* srcRT = static_cast<GrD3DRenderTarget*>(src->asRenderTarget());
487 SkASSERT(srcRT);
488
489 this->resolveTexture(dst, dstPoint.fX, dstPoint.fY, srcRT, srcRect);
490}
491
492void GrD3DGpu::resolveTexture(GrSurface* dst, int32_t dstX, int32_t dstY,
493 GrD3DRenderTarget* src, const SkIRect& srcIRect) {
494 SkASSERT(dst);
495 SkASSERT(src && src->numSamples() > 1 && src->msaaTextureResource());
496
497 D3D12_RECT srcRect = { srcIRect.fLeft, srcIRect.fTop, srcIRect.fRight, srcIRect.fBottom };
498
499 GrD3DTextureResource* dstTextureResource;
500 GrRenderTarget* dstRT = dst->asRenderTarget();
501 if (dstRT) {
502 dstTextureResource = static_cast<GrD3DRenderTarget*>(dstRT);
503 } else {
504 SkASSERT(dst->asTexture());
505 dstTextureResource = static_cast<GrD3DTexture*>(dst->asTexture());
506 }
507
508 dstTextureResource->setResourceState(this, D3D12_RESOURCE_STATE_RESOLVE_DEST);
509 src->msaaTextureResource()->setResourceState(this, D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
510
511 fCurrentDirectCommandList->resolveSubresourceRegion(dstTextureResource, dstX, dstY,
512 src->msaaTextureResource(), &srcRect);
513}
514
Jim Van Verthbb61fe32020-07-07 16:39:04 -0400515void GrD3DGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resolveRect) {
Jim Van Verth275f4192020-07-07 15:36:41 -0400516 SkASSERT(target->numSamples() > 1);
517 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(target);
518 SkASSERT(rt->msaaTextureResource());
519
520 this->resolveTexture(target, resolveRect.fLeft, resolveRect.fTop, rt, resolveRect);
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400521}
522
Jim Van Verthba7f2292020-04-21 08:56:47 -0400523bool GrD3DGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int height,
524 GrColorType surfaceColorType, GrColorType dstColorType, void* buffer,
525 size_t rowBytes) {
526 SkASSERT(surface);
527
528 if (surfaceColorType != dstColorType) {
529 return false;
530 }
531
532 // Set up src location and box
Jim Van Verthc12aad92020-04-24 16:19:01 -0400533 GrD3DTextureResource* texResource = nullptr;
534 GrD3DRenderTarget* rt = static_cast<GrD3DRenderTarget*>(surface->asRenderTarget());
535 if (rt) {
536 texResource = rt;
537 } else {
538 texResource = static_cast<GrD3DTexture*>(surface->asTexture());
539 }
540
541 if (!texResource) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400542 return false;
543 }
Jim Van Verthc12aad92020-04-24 16:19:01 -0400544
Jim Van Verthba7f2292020-04-21 08:56:47 -0400545 D3D12_TEXTURE_COPY_LOCATION srcLocation = {};
Jim Van Verthc12aad92020-04-24 16:19:01 -0400546 srcLocation.pResource = texResource->d3dResource();
Jim Van Verthba7f2292020-04-21 08:56:47 -0400547 SkASSERT(srcLocation.pResource);
548 srcLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
549 srcLocation.SubresourceIndex = 0;
550
551 D3D12_BOX srcBox = {};
552 srcBox.left = left;
553 srcBox.top = top;
554 srcBox.right = left + width;
555 srcBox.bottom = top + height;
556 srcBox.front = 0;
557 srcBox.back = 1;
558
559 // Set up dst location and create transfer buffer
560 D3D12_TEXTURE_COPY_LOCATION dstLocation = {};
561 dstLocation.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400562 UINT64 transferTotalBytes;
563 const UINT64 baseOffset = 0;
564 D3D12_RESOURCE_DESC desc = srcLocation.pResource->GetDesc();
565 fDevice->GetCopyableFootprints(&desc, 0, 1, baseOffset, &dstLocation.PlacedFootprint,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400566 nullptr, nullptr, &transferTotalBytes);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400567 SkASSERT(transferTotalBytes);
Jim Van Verthfdd36852020-04-21 16:29:44 -0400568 size_t bpp = GrColorTypeBytesPerPixel(dstColorType);
Jim Van Verthc12aad92020-04-24 16:19:01 -0400569 if (this->d3dCaps().bytesPerPixel(texResource->dxgiFormat()) != bpp) {
Jim Van Verthfdd36852020-04-21 16:29:44 -0400570 return false;
571 }
572 size_t tightRowBytes = bpp * width;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400573
574 // TODO: implement some way of reusing buffers instead of making a new one every time.
575 sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(transferTotalBytes,
576 GrGpuBufferType::kXferGpuToCpu,
577 kDynamic_GrAccessPattern);
578 GrD3DBuffer* d3dBuf = static_cast<GrD3DBuffer*>(transferBuffer.get());
579 dstLocation.pResource = d3dBuf->d3dResource();
580
581 // Need to change the resource state to COPY_SOURCE in order to download from it
Jim Van Verthc12aad92020-04-24 16:19:01 -0400582 texResource->setResourceState(this, D3D12_RESOURCE_STATE_COPY_SOURCE);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400583
584 fCurrentDirectCommandList->copyTextureRegion(d3dBuf->resource(), &dstLocation, 0, 0,
Jim Van Verthc12aad92020-04-24 16:19:01 -0400585 texResource->resource(), &srcLocation, &srcBox);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400586 this->submitDirectCommandList(SyncQueue::kForce);
587
588 const void* mappedMemory = transferBuffer->map();
589
590 SkRectMemcpy(buffer, rowBytes, mappedMemory, dstLocation.PlacedFootprint.Footprint.RowPitch,
Jim Van Verthfdd36852020-04-21 16:29:44 -0400591 tightRowBytes, height);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400592
593 transferBuffer->unmap();
594
595 return true;
596}
597
598bool GrD3DGpu::onWritePixels(GrSurface* surface, int left, int top, int width, int height,
599 GrColorType surfaceColorType, GrColorType srcColorType,
600 const GrMipLevel texels[], int mipLevelCount,
601 bool prepForTexSampling) {
602 GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(surface->asTexture());
603 if (!d3dTex) {
604 return false;
605 }
606
607 // Make sure we have at least the base level
608 if (!mipLevelCount || !texels[0].fPixels) {
609 return false;
610 }
611
612 SkASSERT(!GrDxgiFormatIsCompressed(d3dTex->dxgiFormat()));
613 bool success = false;
614
615 // Need to change the resource state to COPY_DEST in order to upload to it
616 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
617
618 SkASSERT(mipLevelCount <= d3dTex->texturePriv().maxMipMapLevel() + 1);
619 success = this->uploadToTexture(d3dTex, left, top, width, height, srcColorType, texels,
620 mipLevelCount);
621
622 if (prepForTexSampling) {
623 d3dTex->setResourceState(this, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
624 }
625
626 return success;
627}
628
629bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, int height,
630 GrColorType colorType, const GrMipLevel* texels, int mipLevelCount) {
631 SkASSERT(this->caps()->isFormatTexturable(tex->backendFormat()));
632 // The assumption is either that we have no mipmaps, or that our rect is the entire texture
633 SkASSERT(1 == mipLevelCount ||
634 (0 == left && 0 == top && width == tex->width() && height == tex->height()));
635
636 // We assume that if the texture has mip levels, we either upload to all the levels or just the
637 // first.
638 SkASSERT(1 == mipLevelCount || mipLevelCount == (tex->texturePriv().maxMipMapLevel() + 1));
639
640 if (width == 0 || height == 0) {
641 return false;
642 }
643
644 SkASSERT(this->d3dCaps().surfaceSupportsWritePixels(tex));
645 SkASSERT(this->d3dCaps().areColorTypeAndFormatCompatible(colorType, tex->backendFormat()));
646
647 ID3D12Resource* d3dResource = tex->d3dResource();
648 SkASSERT(d3dResource);
649 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
650 // Either upload only the first miplevel or all miplevels
651 SkASSERT(1 == mipLevelCount || mipLevelCount == (int)desc.MipLevels);
652
653 if (1 == mipLevelCount && !texels[0].fPixels) {
654 return true; // no data to upload
655 }
656
657 for (int i = 0; i < mipLevelCount; ++i) {
658 // We do not allow any gaps in the mip data
659 if (!texels[i].fPixels) {
660 return false;
661 }
662 }
663
664 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400665 UINT64 combinedBufferSize;
666 // We reset the width and height in the description to match our subrectangle size
667 // so we don't end up allocating more space than we need.
668 desc.Width = width;
669 desc.Height = height;
670 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthfdd36852020-04-21 16:29:44 -0400671 nullptr, nullptr, &combinedBufferSize);
672 size_t bpp = GrColorTypeBytesPerPixel(colorType);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400673 SkASSERT(combinedBufferSize);
674
Greg Danielcffb0622020-07-16 13:19:17 -0400675 GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
676 combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
677 if (!slice.fBuffer) {
Jim Van Verthba7f2292020-04-21 08:56:47 -0400678 return false;
679 }
Greg Danielcffb0622020-07-16 13:19:17 -0400680
681 char* bufferData = (char*)slice.fOffsetMapPtr;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400682
683 int currentWidth = width;
684 int currentHeight = height;
685 int layerHeight = tex->height();
686
687 for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) {
688 if (texels[currentMipLevel].fPixels) {
689 SkASSERT(1 == mipLevelCount || currentHeight == layerHeight);
690
Jim Van Verthfdd36852020-04-21 16:29:44 -0400691 const size_t trimRowBytes = currentWidth * bpp;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400692 const size_t srcRowBytes = texels[currentMipLevel].fRowBytes;
693
694 char* dst = bufferData + placedFootprints[currentMipLevel].Offset;
695
696 // copy data into the buffer, skipping any trailing bytes
Jim Van Verthba7f2292020-04-21 08:56:47 -0400697 const char* src = (const char*)texels[currentMipLevel].fPixels;
Jim Van Verthba7f2292020-04-21 08:56:47 -0400698 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
699 src, srcRowBytes, trimRowBytes, currentHeight);
700 }
701 currentWidth = std::max(1, currentWidth / 2);
702 currentHeight = std::max(1, currentHeight / 2);
703 layerHeight = currentHeight;
704 }
705
Greg Danielcffb0622020-07-16 13:19:17 -0400706 // Update the offsets in the footprints to be relative to the slice's offset
707 for (int i = 0; i < mipLevelCount; ++i) {
708 placedFootprints[i].Offset += slice.fOffset;
709 }
Jim Van Verthba7f2292020-04-21 08:56:47 -0400710
Greg Danielcffb0622020-07-16 13:19:17 -0400711 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer);
Jim Van Verthba7f2292020-04-21 08:56:47 -0400712 fCurrentDirectCommandList->copyBufferToTexture(d3dBuffer, tex, mipLevelCount,
713 placedFootprints.get(), left, top);
714
715 if (mipLevelCount < (int)desc.MipLevels) {
716 tex->texturePriv().markMipMapsDirty();
717 }
718
719 return true;
720}
721
Jim Van Verth9145f782020-04-28 12:01:12 -0400722static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
723 if (!info.fResource.get()) {
724 return false;
725 }
726 return true;
727}
728
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400729static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
730 if (!caps.isFormatTexturable(info.fFormat)) {
731 return false;
732 }
733 return true;
734}
735
736static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
737 int sampleCnt) {
738 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
739 return false;
740 }
741 return true;
742}
743
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400744sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
745 GrWrapOwnership,
746 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400747 GrIOType ioType) {
748 GrD3DTextureResourceInfo textureInfo;
749 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
750 return nullptr;
751 }
752
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400753 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400754 return nullptr;
755 }
756
757 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
758 return nullptr;
759 }
760
761 // TODO: support protected context
762 if (tex.isProtected()) {
763 return nullptr;
764 }
765
766 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
767 SkASSERT(state);
768 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
769 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500770}
771
772sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400773 GrWrapOwnership ownership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500774 GrWrapCacheable wrapType) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -0400775 return this->onWrapBackendTexture(tex, ownership, wrapType, kRead_GrIOType);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500776}
777
778sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
779 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500780 GrWrapOwnership ownership,
781 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400782 GrD3DTextureResourceInfo textureInfo;
783 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
784 return nullptr;
785 }
786
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400787 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400788 return nullptr;
789 }
790
791 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
792 return nullptr;
793 }
794 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
795 return nullptr;
796 }
797
798 // TODO: support protected context
799 if (tex.isProtected()) {
800 return nullptr;
801 }
802
803 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
804
805 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
806 SkASSERT(state);
807
808 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
809 sampleCnt, cacheable,
810 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500811}
812
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400813sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400814 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
815 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
816 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
817 // creating and owning the MSAA images.
818 if (rt.sampleCnt() > 1) {
819 return nullptr;
820 }
821
822 GrD3DTextureResourceInfo info;
823 if (!rt.getD3DTextureResourceInfo(&info)) {
824 return nullptr;
825 }
826
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400827 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400828 return nullptr;
829 }
830
831 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
832 return nullptr;
833 }
834
835 // TODO: support protected context
836 if (rt.isProtected()) {
837 return nullptr;
838 }
839
840 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
841
842 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
843 this, rt.dimensions(), 1, info, std::move(state));
844
845 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
846 SkASSERT(!rt.stencilBits());
847 if (tgt) {
848 SkASSERT(tgt->canAttemptStencilAttachment());
849 }
850
851 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500852}
853
854sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400855 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400856
857 GrD3DTextureResourceInfo textureInfo;
858 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
859 return nullptr;
860 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400861 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400862 return nullptr;
863 }
864
865 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
866 return nullptr;
867 }
868
869 // TODO: support protected context
870 if (tex.isProtected()) {
871 return nullptr;
872 }
873
874 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
875 if (!sampleCnt) {
876 return nullptr;
877 }
878
879 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
880 SkASSERT(state);
881
882 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
883 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500884}
885
886sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400887 GrAccessPattern accessPattern, const void* data) {
888 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
889 if (data && buffer) {
890 buffer->updateData(data, sizeInBytes);
891 }
892
893 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500894}
895
896GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
897 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
Jim Van Verth4f51f472020-04-13 11:02:21 -0400898 SkASSERT(numStencilSamples == rt->numSamples() || this->caps()->mixedSamplesSupport());
899 SkASSERT(width >= rt->width());
900 SkASSERT(height >= rt->height());
901
902 const GrD3DCaps::StencilFormat& sFmt = this->d3dCaps().preferredStencilFormat();
903
904 GrD3DStencilAttachment* stencil(GrD3DStencilAttachment::Make(this,
905 width,
906 height,
907 numStencilSamples,
908 sFmt));
909 fStats.incStencilAttachmentCreates();
910 return stencil;
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500911}
912
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400913bool GrD3DGpu::createTextureResourceForBackendSurface(DXGI_FORMAT dxgiFormat,
914 SkISize dimensions,
915 GrTexturable texturable,
916 GrRenderable renderable,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400917 GrMipmapped mipMapped,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400918 GrD3DTextureResourceInfo* info,
Greg Daniel16032b32020-05-06 15:31:10 -0400919 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400920 SkASSERT(texturable == GrTexturable::kYes || renderable == GrRenderable::kYes);
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400921
922 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
923 return false;
924 }
925
926 if (texturable == GrTexturable::kYes && !this->d3dCaps().isFormatTexturable(dxgiFormat)) {
927 return false;
928 }
929
930 if (renderable == GrRenderable::kYes && !this->d3dCaps().isFormatRenderable(dxgiFormat, 1)) {
931 return false;
932 }
933
934 int numMipLevels = 1;
Brian Salomon7e67dca2020-07-21 09:27:25 -0400935 if (mipMapped == GrMipmapped::kYes) {
Mike Reed13711eb2020-07-14 17:16:32 -0400936 numMipLevels = SkMipmap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1;
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400937 }
938
939 // create the texture
940 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
941 if (renderable == GrRenderable::kYes) {
942 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
943 }
944
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400945 D3D12_RESOURCE_DESC resourceDesc = {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400946 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
Greg Daniel16032b32020-05-06 15:31:10 -0400947 resourceDesc.Alignment = 0; // use default alignment
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400948 resourceDesc.Width = dimensions.fWidth;
949 resourceDesc.Height = dimensions.fHeight;
950 resourceDesc.DepthOrArraySize = 1;
951 resourceDesc.MipLevels = numMipLevels;
952 resourceDesc.Format = dxgiFormat;
953 resourceDesc.SampleDesc.Count = 1;
Greg Danielc9624d52020-04-13 15:36:31 -0400954 // quality levels are only supported for tiled resources so ignore for now
955 resourceDesc.SampleDesc.Quality = GrD3DTextureResource::kDefaultQualityLevel;
Greg Daniel16032b32020-05-06 15:31:10 -0400956 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400957 resourceDesc.Flags = usageFlags;
958
Jim Van Verth280d4f72020-05-04 10:04:24 -0400959 D3D12_CLEAR_VALUE* clearValuePtr = nullptr;
960 D3D12_CLEAR_VALUE clearValue = {};
961 if (renderable == GrRenderable::kYes) {
962 clearValue.Format = dxgiFormat;
963 // Assume transparent black
964 clearValue.Color[0] = 0;
965 clearValue.Color[1] = 0;
966 clearValue.Color[2] = 0;
967 clearValue.Color[3] = 0;
968 clearValuePtr = &clearValue;
969 }
970
Greg Daniel16032b32020-05-06 15:31:10 -0400971 D3D12_RESOURCE_STATES initialState = (renderable == GrRenderable::kYes)
972 ? D3D12_RESOURCE_STATE_RENDER_TARGET
973 : D3D12_RESOURCE_STATE_COPY_DEST;
Jim Van Verth2b9f53e2020-04-14 11:47:34 -0400974 if (!GrD3DTextureResource::InitTextureResourceInfo(this, resourceDesc, initialState,
Jim Van Verth280d4f72020-05-04 10:04:24 -0400975 isProtected, clearValuePtr, info)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400976 SkDebugf("Failed to init texture resource info\n");
977 return false;
978 }
979
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400980 return true;
981}
982
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500983GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400984 const GrBackendFormat& format,
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400985 GrRenderable renderable,
Brian Salomon7e67dca2020-07-21 09:27:25 -0400986 GrMipmapped mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -0400987 GrProtected isProtected) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -0400988 this->handleDirtyContext();
989
990 const GrD3DCaps& caps = this->d3dCaps();
991
992 if (this->protectedContext() != (isProtected == GrProtected::kYes)) {
993 return {};
994 }
995
996 DXGI_FORMAT dxgiFormat;
997 if (!format.asDxgiFormat(&dxgiFormat)) {
998 return {};
999 }
1000
1001 // TODO: move the texturability check up to GrGpu::createBackendTexture and just assert here
1002 if (!caps.isFormatTexturable(dxgiFormat)) {
1003 return {};
1004 }
1005
1006 GrD3DTextureResourceInfo info;
1007 if (!this->createTextureResourceForBackendSurface(dxgiFormat, dimensions, GrTexturable::kYes,
1008 renderable, mipMapped,
Greg Daniel16032b32020-05-06 15:31:10 -04001009 &info, isProtected)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001010 return {};
1011 }
1012
1013 return GrBackendTexture(dimensions.width(), dimensions.height(), info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001014}
1015
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001016static void copy_src_data(GrD3DGpu* gpu, char* mapPtr, DXGI_FORMAT dxgiFormat,
1017 D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
1018 const SkPixmap srcData[], int numMipLevels) {
Jim Van Verth43a6e172020-06-23 11:59:08 -04001019 SkASSERT(srcData && numMipLevels);
1020 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
1021 SkASSERT(mapPtr);
1022
1023 size_t bytesPerPixel = gpu->d3dCaps().bytesPerPixel(dxgiFormat);
1024
1025 for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) {
1026 const size_t trimRowBytes = srcData[currentMipLevel].width() * bytesPerPixel;
1027
1028 // copy data into the buffer, skipping any trailing bytes
1029 char* dst = mapPtr + placedFootprints[currentMipLevel].Offset;
1030 SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch,
1031 srcData[currentMipLevel].addr(), srcData[currentMipLevel].rowBytes(),
1032 trimRowBytes, srcData[currentMipLevel].height());
1033 }
Jim Van Verth43a6e172020-06-23 11:59:08 -04001034}
1035
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001036static bool copy_color_data(const GrD3DCaps& caps, char* mapPtr,
1037 DXGI_FORMAT dxgiFormat, SkISize dimensions,
1038 D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints,
1039 SkColor4f color) {
Greg Daniel746460e2020-06-30 13:13:53 -04001040 auto colorType = caps.getFormatColorType(dxgiFormat);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001041 if (colorType == GrColorType::kUnknown) {
1042 return false;
1043 }
1044 GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, dimensions);
1045 if (!GrClearImage(ii, mapPtr, placedFootprints[0].Footprint.RowPitch, color)) {
1046 return false;
1047 }
1048
1049 return true;
1050}
1051
Greg Daniel16032b32020-05-06 15:31:10 -04001052bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture,
1053 sk_sp<GrRefCntedCallback> finishedCallback,
1054 const BackendTextureData* data) {
Jim Van Verth43a6e172020-06-23 11:59:08 -04001055 GrD3DTextureResourceInfo info;
1056 SkAssertResult(backendTexture.getD3DTextureResourceInfo(&info));
1057
1058 sk_sp<GrD3DResourceState> state = backendTexture.getGrD3DResourceState();
1059 SkASSERT(state);
1060 sk_sp<GrD3DTexture> texture =
1061 GrD3DTexture::MakeWrappedTexture(this, backendTexture.dimensions(),
1062 GrWrapCacheable::kNo,
1063 kRW_GrIOType, info, std::move(state));
1064 if (!texture) {
1065 return false;
1066 }
1067
1068 GrD3DDirectCommandList* cmdList = this->currentCommandList();
1069 if (!cmdList) {
1070 return false;
1071 }
1072
1073 texture->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST);
1074
1075 ID3D12Resource* d3dResource = texture->d3dResource();
1076 SkASSERT(d3dResource);
1077 D3D12_RESOURCE_DESC desc = d3dResource->GetDesc();
1078 unsigned int mipLevelCount = 1;
Brian Salomon7e67dca2020-07-21 09:27:25 -04001079 if (backendTexture.fMipMapped == GrMipmapped::kYes) {
Mike Reed13711eb2020-07-14 17:16:32 -04001080 mipLevelCount = SkMipmap::ComputeLevelCount(backendTexture.dimensions().width(),
Jim Van Verth43a6e172020-06-23 11:59:08 -04001081 backendTexture.dimensions().height()) + 1;
1082 }
1083 SkASSERT(mipLevelCount == info.fLevelCount);
1084 SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount);
1085 UINT64 combinedBufferSize;
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001086 SkAutoTMalloc<UINT> numRows(mipLevelCount);
1087 SkAutoTMalloc<UINT64> rowSizeInBytes(mipLevelCount);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001088 fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(),
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001089 numRows.get(), rowSizeInBytes.get(), &combinedBufferSize);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001090 SkASSERT(combinedBufferSize);
1091 if (data->type() == BackendTextureData::Type::kColor &&
1092 !GrDxgiFormatIsCompressed(info.fFormat) && mipLevelCount > 1) {
1093 // For a single uncompressed color, we reuse the same top-level buffer area for all levels.
1094 combinedBufferSize =
1095 placedFootprints[0].Footprint.RowPitch * placedFootprints[0].Footprint.Height;
1096 for (unsigned int i = 1; i < mipLevelCount; ++i) {
1097 placedFootprints[i].Offset = 0;
1098 placedFootprints[i].Footprint.RowPitch = placedFootprints[0].Footprint.RowPitch;
1099 }
1100 }
1101
Greg Danielcffb0622020-07-16 13:19:17 -04001102 GrStagingBufferManager::Slice slice = fStagingBufferManager.allocateStagingBufferSlice(
1103 combinedBufferSize, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT);
1104 if (!slice.fBuffer) {
Jim Van Verth43a6e172020-06-23 11:59:08 -04001105 return false;
1106 }
Greg Danielcffb0622020-07-16 13:19:17 -04001107
1108 char* bufferData = (char*)slice.fOffsetMapPtr;
Jim Van Verth43a6e172020-06-23 11:59:08 -04001109 SkASSERT(bufferData);
1110
Jim Van Verth43a6e172020-06-23 11:59:08 -04001111 if (data->type() == BackendTextureData::Type::kPixmaps) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001112 copy_src_data(this, bufferData, info.fFormat, placedFootprints.get(), data->pixmaps(),
1113 info.fLevelCount);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001114 } else if (data->type() == BackendTextureData::Type::kCompressed) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001115 copy_compressed_data(bufferData, info.fFormat, placedFootprints.get(), numRows.get(),
1116 rowSizeInBytes.get(), data->compressedData(), info.fLevelCount);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001117 } else {
1118 SkASSERT(data->type() == BackendTextureData::Type::kColor);
1119 SkImage::CompressionType compression =
1120 GrBackendFormatToCompressionType(backendTexture.getBackendFormat());
1121 if (SkImage::CompressionType::kNone == compression) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001122 if (!copy_color_data(this->d3dCaps(), bufferData, info.fFormat,
1123 backendTexture.dimensions(), placedFootprints, data->color())) {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001124 return false;
1125 }
Jim Van Verth43a6e172020-06-23 11:59:08 -04001126 } else {
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001127 size_t totalCompressedSize = SkCompressedFormatDataSize(compression,
1128 backendTexture.dimensions(),
1129 backendTexture.hasMipMaps());
1130 SkAutoTMalloc<char> tempData(totalCompressedSize);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001131 GrFillInCompressedData(compression, backendTexture.dimensions(),
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001132 backendTexture.fMipMapped, tempData, data->color());
1133 copy_compressed_data(bufferData, info.fFormat, placedFootprints.get(), numRows.get(),
1134 rowSizeInBytes.get(), tempData.get(), info.fLevelCount);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001135 }
1136 }
Jim Van Verth43a6e172020-06-23 11:59:08 -04001137
Greg Danielcffb0622020-07-16 13:19:17 -04001138 // Update the offsets in the footprints to be relative to the slice's offset
1139 for (unsigned int i = 0; i < mipLevelCount; ++i) {
1140 placedFootprints[i].Offset += slice.fOffset;
1141 }
1142
1143 GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer);
1144 cmdList->copyBufferToTexture(d3dBuffer, texture.get(), mipLevelCount, placedFootprints.get(), 0,
1145 0);
Jim Van Verth43a6e172020-06-23 11:59:08 -04001146
1147 if (finishedCallback) {
1148 this->addFinishedCallback(std::move(finishedCallback));
1149 }
1150
Greg Daniel16032b32020-05-06 15:31:10 -04001151 return true;
1152}
1153
Greg Danielc1ad77c2020-05-06 11:40:03 -04001154GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(
Brian Salomon7e67dca2020-07-21 09:27:25 -04001155 SkISize dimensions, const GrBackendFormat& format, GrMipmapped mipMapped,
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001156 GrProtected isProtected) {
1157 return this->onCreateBackendTexture(dimensions, format, GrRenderable::kNo, mipMapped,
1158 isProtected);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001159}
1160
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001161bool GrD3DGpu::onUpdateCompressedBackendTexture(const GrBackendTexture& backendTexture,
Greg Danielaaf738c2020-07-10 09:30:33 -04001162 sk_sp<GrRefCntedCallback> finishedCallback,
Jim Van Verthbb80fcd2020-07-14 10:04:40 -04001163 const BackendTextureData* data) {
1164 return this->onUpdateBackendTexture(backendTexture, std::move(finishedCallback), data);
Greg Danielaaf738c2020-07-10 09:30:33 -04001165}
1166
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001167void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001168 SkASSERT(GrBackendApi::kDirect3D == tex.fBackend);
1169 // Nothing to do here, will get cleaned up when the GrBackendTexture object goes away
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001170}
1171
Robert Phillips979b2232020-02-20 10:47:29 -05001172bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
1173 return false;
1174}
1175
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001176#if GR_TEST_UTILS
1177bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001178 SkASSERT(GrBackendApi::kDirect3D == tex.backend());
1179
1180 GrD3DTextureResourceInfo info;
1181 if (!tex.getD3DTextureResourceInfo(&info)) {
1182 return false;
1183 }
1184 ID3D12Resource* textureResource = info.fResource.get();
1185 if (!textureResource) {
1186 return false;
1187 }
1188 return !(textureResource->GetDesc().Flags & D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001189}
1190
1191GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -04001192 GrColorType colorType) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001193 this->handleDirtyContext();
1194
1195 if (w > this->caps()->maxRenderTargetSize() || h > this->caps()->maxRenderTargetSize()) {
Jim Van Verth2b9f53e2020-04-14 11:47:34 -04001196 return {};
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001197 }
1198
1199 DXGI_FORMAT dxgiFormat = this->d3dCaps().getFormatFromColorType(colorType);
1200
1201 GrD3DTextureResourceInfo info;
1202 if (!this->createTextureResourceForBackendSurface(dxgiFormat, { w, h }, GrTexturable::kNo,
Brian Salomon7e67dca2020-07-21 09:27:25 -04001203 GrRenderable::kYes, GrMipmapped::kNo,
Greg Daniel16032b32020-05-06 15:31:10 -04001204 &info, GrProtected::kNo)) {
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001205 return {};
1206 }
1207
1208 return GrBackendRenderTarget(w, h, 1, info);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -05001209}
1210
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001211void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget& rt) {
1212 SkASSERT(GrBackendApi::kDirect3D == rt.backend());
1213
1214 GrD3DTextureResourceInfo info;
1215 if (rt.getD3DTextureResourceInfo(&info)) {
1216 this->testingOnly_flushGpuAndSync();
1217 // Nothing else to do here, will get cleaned up when the GrBackendRenderTarget
1218 // is deleted.
1219 }
1220}
1221
1222void GrD3DGpu::testingOnly_flushGpuAndSync() {
Jim Van Verthc632aa62020-04-17 16:58:20 -04001223 SkAssertResult(this->submitDirectCommandList(SyncQueue::kForce));
Jim Van Verth96bfeff2020-04-09 14:36:12 -04001224}
Jim Van Verthc632aa62020-04-17 16:58:20 -04001225
Jim Van Verth9b5e16c2020-04-20 10:45:52 -04001226void GrD3DGpu::testingOnly_startCapture() {
1227 if (fGraphicsAnalysis) {
1228 fGraphicsAnalysis->BeginCapture();
1229 }
1230}
1231
1232void GrD3DGpu::testingOnly_endCapture() {
1233 if (fGraphicsAnalysis) {
1234 fGraphicsAnalysis->EndCapture();
1235 }
1236}
1237#endif
1238
Jim Van Verthc632aa62020-04-17 16:58:20 -04001239///////////////////////////////////////////////////////////////////////////////
1240
Greg Daniela5a6b322020-04-23 12:52:27 -04001241void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource,
Jim Van Verthc632aa62020-04-17 16:58:20 -04001242 int numBarriers,
1243 D3D12_RESOURCE_TRANSITION_BARRIER* barriers) const {
1244 SkASSERT(fCurrentDirectCommandList);
1245 SkASSERT(resource);
1246
Greg Daniela5a6b322020-04-23 12:52:27 -04001247 fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers);
Jim Van Verthc632aa62020-04-17 16:58:20 -04001248}
1249
Greg Daniel9efe3862020-06-11 11:51:06 -04001250void GrD3DGpu::prepareSurfacesForBackendAccessAndStateUpdates(
1251 GrSurfaceProxy* proxies[],
1252 int numProxies,
1253 SkSurface::BackendSurfaceAccess access,
1254 const GrBackendSurfaceMutableState* newState) {
Jim Van Verth682a2f42020-05-13 16:54:09 -04001255 SkASSERT(numProxies >= 0);
1256 SkASSERT(!numProxies || proxies);
1257
1258 // prepare proxies by transitioning to PRESENT renderState
1259 if (numProxies && access == SkSurface::BackendSurfaceAccess::kPresent) {
1260 GrD3DTextureResource* resource;
1261 for (int i = 0; i < numProxies; ++i) {
1262 SkASSERT(proxies[i]->isInstantiated());
1263 if (GrTexture* tex = proxies[i]->peekTexture()) {
1264 resource = static_cast<GrD3DTexture*>(tex);
1265 } else {
1266 GrRenderTarget* rt = proxies[i]->peekRenderTarget();
1267 SkASSERT(rt);
1268 resource = static_cast<GrD3DRenderTarget*>(rt);
1269 }
1270 resource->prepareForPresent(this);
1271 }
1272 }
1273}
1274
Greg Danielcffb0622020-07-16 13:19:17 -04001275void GrD3DGpu::takeOwnershipOfStagingBuffer(sk_sp<GrGpuBuffer> buffer) {
Greg Daniel426274b2020-07-20 11:37:38 -04001276 fCurrentDirectCommandList->addGrBuffer(std::move(buffer));
Greg Danielcffb0622020-07-16 13:19:17 -04001277}
1278
Jim Van Verthc632aa62020-04-17 16:58:20 -04001279bool GrD3DGpu::onSubmitToGpu(bool syncCpu) {
1280 if (syncCpu) {
1281 return this->submitDirectCommandList(SyncQueue::kForce);
1282 } else {
1283 return this->submitDirectCommandList(SyncQueue::kSkip);
1284 }
1285}
Jim Van Verthc1a67b52020-06-25 13:10:29 -04001286
1287std::unique_ptr<GrSemaphore> SK_WARN_UNUSED_RESULT GrD3DGpu::makeSemaphore(bool) {
1288 return GrD3DSemaphore::Make(this);
1289}
1290std::unique_ptr<GrSemaphore> GrD3DGpu::wrapBackendSemaphore(
1291 const GrBackendSemaphore& semaphore,
1292 GrResourceProvider::SemaphoreWrapType,
1293 GrWrapOwnership) {
1294 SkASSERT(this->caps()->semaphoreSupport());
1295 GrD3DFenceInfo fenceInfo;
1296 if (!semaphore.getD3DFenceInfo(&fenceInfo)) {
1297 return nullptr;
1298 }
1299 return GrD3DSemaphore::MakeWrapped(fenceInfo);
1300}
1301
1302void GrD3DGpu::insertSemaphore(GrSemaphore* semaphore) {
Greg Daniel0106fcc2020-07-01 17:40:12 -04001303 SkASSERT(semaphore);
Jim Van Verthc1a67b52020-06-25 13:10:29 -04001304 GrD3DSemaphore* d3dSem = static_cast<GrD3DSemaphore*>(semaphore);
1305 // TODO: Do we need to track the lifetime of this? How do we know it's done?
1306 fQueue->Signal(d3dSem->fence(), d3dSem->value());
1307}
1308
1309void GrD3DGpu::waitSemaphore(GrSemaphore* semaphore) {
Greg Daniel0106fcc2020-07-01 17:40:12 -04001310 SkASSERT(semaphore);
Jim Van Verthc1a67b52020-06-25 13:10:29 -04001311 GrD3DSemaphore* d3dSem = static_cast<GrD3DSemaphore*>(semaphore);
1312 // TODO: Do we need to track the lifetime of this?
1313 fQueue->Wait(d3dSem->fence(), d3dSem->value());
1314}
Jim Van Verth1e6460d2020-06-30 15:47:52 -04001315
1316GrFence SK_WARN_UNUSED_RESULT GrD3DGpu::insertFence() {
Jim Van Verthe3810362020-07-01 10:12:11 -04001317 GR_D3D_CALL_ERRCHECK(fQueue->Signal(fFence.get(), ++fCurrentFenceValue));
Jim Van Verth1e6460d2020-06-30 15:47:52 -04001318 return fCurrentFenceValue;
1319}
1320
1321bool GrD3DGpu::waitFence(GrFence fence) {
Jim Van Verth3b0d7d12020-07-06 11:52:42 -04001322 return (fFence->GetCompletedValue() >= fence);
Jim Van Verth1e6460d2020-06-30 15:47:52 -04001323}