blob: b8b85fe2cf2265c575f428efb88c27e065205e42 [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 Verth9aa9a682020-04-01 10:13:48 -040010#include "include/gpu/d3d/GrD3DBackendContext.h"
Jim Van Verthd6ad4802020-04-03 14:59:20 -040011#include "src/gpu/d3d/GrD3DBuffer.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050012#include "src/gpu/d3d/GrD3DCaps.h"
13#include "src/gpu/d3d/GrD3DOpsRenderPass.h"
Jim Van Verthaa90dad2020-03-30 15:00:39 -040014#include "src/gpu/d3d/GrD3DTexture.h"
15#include "src/gpu/d3d/GrD3DTextureRenderTarget.h"
16#include "src/gpu/d3d/GrD3DUtil.h"
Greg Daniel31a7b072020-02-26 15:31:49 -050017
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050018sk_sp<GrGpu> GrD3DGpu::Make(const GrD3DBackendContext& backendContext,
19 const GrContextOptions& contextOptions, GrContext* context) {
20 return sk_sp<GrGpu>(new GrD3DGpu(context, contextOptions, backendContext));
21}
22
Greg Daniel83ed2132020-03-24 13:15:33 -040023// This constant determines how many OutstandingCommandLists are allocated together as a block in
24// the deque. As such it needs to balance allocating too much memory vs. incurring
25// allocation/deallocation thrashing. It should roughly correspond to the max number of outstanding
26// command lists we expect to see.
27static const int kDefaultOutstandingAllocCnt = 8;
28
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050029GrD3DGpu::GrD3DGpu(GrContext* context, const GrContextOptions& contextOptions,
30 const GrD3DBackendContext& backendContext)
Jim Van Verth03b8ab22020-02-24 11:36:15 -050031 : INHERITED(context)
32 , fDevice(backendContext.fDevice)
Greg Daniel02c45902020-03-09 10:58:09 -040033
34 , fQueue(backendContext.fQueue)
Greg Daniel83ed2132020-03-24 13:15:33 -040035 , fResourceProvider(this)
36 , fOutstandingCommandLists(sizeof(OutstandingCommandList), kDefaultOutstandingAllocCnt) {
Jim Van Verth8ec13302020-02-26 12:59:56 -050037 fCaps.reset(new GrD3DCaps(contextOptions,
Jim Van Verth9aa9a682020-04-01 10:13:48 -040038 backendContext.fAdapter.get(),
39 backendContext.fDevice.get()));
Greg Daniel85da3362020-03-09 15:18:35 -040040
41 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
Greg Daniele52c9782020-03-23 14:18:37 -040042 SkASSERT(fCurrentDirectCommandList);
Greg Daniel83ed2132020-03-24 13:15:33 -040043
44 SkASSERT(fCurrentFenceValue == 0);
45 SkDEBUGCODE(HRESULT hr = ) fDevice->CreateFence(fCurrentFenceValue, D3D12_FENCE_FLAG_NONE,
46 IID_PPV_ARGS(&fFence));
47 SkASSERT(SUCCEEDED(hr));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050048}
49
Greg Daniel83ed2132020-03-24 13:15:33 -040050GrD3DGpu::~GrD3DGpu() {
51 this->destroyResources();
52}
53
54void GrD3DGpu::destroyResources() {
55 if (fCurrentDirectCommandList) {
56 fCurrentDirectCommandList->close();
57 fCurrentDirectCommandList.reset();
58 }
59
60 // We need to make sure everything has finished on the queue.
61 if (fFence->GetCompletedValue() < fCurrentFenceValue) {
62 HANDLE fenceEvent;
63 fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
64 SkASSERT(fenceEvent);
65 SkDEBUGCODE(HRESULT hr = ) fFence->SetEventOnCompletion(fCurrentFenceValue, fenceEvent);
66 SkASSERT(SUCCEEDED(hr));
67 WaitForSingleObject(fenceEvent, INFINITE);
68 CloseHandle(fenceEvent);
69 }
70
71 SkDEBUGCODE(uint64_t fenceValue = fFence->GetCompletedValue();)
72
73 // We used a placement new for each object in fOutstandingCommandLists, so we're responsible
74 // for calling the destructor on each of them as well.
75 while (!fOutstandingCommandLists.empty()) {
76 OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.back();
77 SkASSERT(list->fFenceValue <= fenceValue);
78 // No reason to recycle the command lists since we are destroying all resources anyways.
79 list->~OutstandingCommandList();
80 fOutstandingCommandLists.pop_back();
81 }
82}
Greg Daniel31a7b072020-02-26 15:31:49 -050083
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050084GrOpsRenderPass* GrD3DGpu::getOpsRenderPass(
85 GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds,
86 const GrOpsRenderPass::LoadAndStoreInfo& colorInfo,
Greg Daniel31a7b072020-02-26 15:31:49 -050087 const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050088 const SkTArray<GrSurfaceProxy*, true>& sampledProxies) {
Greg Daniel31a7b072020-02-26 15:31:49 -050089 if (!fCachedOpsRenderPass) {
90 fCachedOpsRenderPass.reset(new GrD3DOpsRenderPass(this));
91 }
92
93 if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) {
94 return nullptr;
95 }
96 return fCachedOpsRenderPass.get();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -050097}
98
Greg Daniel83ed2132020-03-24 13:15:33 -040099void GrD3DGpu::submitDirectCommandList() {
100 SkASSERT(fCurrentDirectCommandList);
101
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400102 fCurrentDirectCommandList->submit(fQueue.get());
Greg Daniel83ed2132020-03-24 13:15:33 -0400103
104 new (fOutstandingCommandLists.push_back()) OutstandingCommandList(
105 std::move(fCurrentDirectCommandList), ++fCurrentFenceValue);
106
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400107 SkDEBUGCODE(HRESULT hr = ) fQueue->Signal(fFence.get(), fCurrentFenceValue);
Greg Daniel83ed2132020-03-24 13:15:33 -0400108 SkASSERT(SUCCEEDED(hr));
109
110 fCurrentDirectCommandList = fResourceProvider.findOrCreateDirectCommandList();
111
112 // This should be done after we have a new command list in case the freeing of any resources
113 // held by a finished command list causes us send a new command to the gpu (like changing the
114 // resource state.
115 this->checkForFinishedCommandLists();
116
117 SkASSERT(fCurrentDirectCommandList);
118}
119
120void GrD3DGpu::checkForFinishedCommandLists() {
121 uint64_t currentFenceValue = fFence->GetCompletedValue();
122
123 // Iterate over all the outstanding command lists to see if any have finished. The commands
124 // lists are in order from oldest to newest, so we start at the front to check if their fence
125 // value is less than the last signaled value. If so we pop it off and move onto the next.
126 // Repeat till we find a command list that has not finished yet (and all others afterwards are
127 // also guaranteed to not have finished).
128 SkDeque::F2BIter iter(fOutstandingCommandLists);
129 const OutstandingCommandList* curList = (const OutstandingCommandList*)iter.next();
130 while (curList && curList->fFenceValue <= currentFenceValue) {
131 curList = (const OutstandingCommandList*)iter.next();
132 OutstandingCommandList* front = (OutstandingCommandList*)fOutstandingCommandLists.front();
Greg Daniel7a5f1fa2020-03-24 14:50:19 -0400133 fResourceProvider.recycleDirectCommandList(std::move(front->fCommandList));
Greg Daniel83ed2132020-03-24 13:15:33 -0400134 // Since we used placement new we are responsible for calling the destructor manually.
135 front->~OutstandingCommandList();
136 fOutstandingCommandLists.pop_front();
137 }
138}
139
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500140void GrD3DGpu::submit(GrOpsRenderPass* renderPass) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400141 SkASSERT(fCachedOpsRenderPass.get() == renderPass);
142
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500143 // TODO: actually submit something here
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400144 fCachedOpsRenderPass.reset();
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500145}
146
147void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) {
148 // TODO
149}
150
151sk_sp<GrTexture> GrD3DGpu::onCreateTexture(SkISize dimensions,
152 const GrBackendFormat& format,
153 GrRenderable renderable,
154 int renderTargetSampleCnt,
155 SkBudgeted budgeted,
156 GrProtected isProtected,
157 int mipLevelCount,
158 uint32_t levelClearMask) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400159 DXGI_FORMAT dxgiFormat;
160 SkAssertResult(format.asDxgiFormat(&dxgiFormat));
161 SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat));
162
163 D3D12_RESOURCE_FLAGS usageFlags = D3D12_RESOURCE_FLAG_NONE;
164
165 if (renderable == GrRenderable::kYes) {
166 usageFlags |= D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET;
167 }
168
169 // This desc refers to the texture that will be read by the client. Thus even if msaa is
170 // requested, this describes the resolved texture. Therefore we always have samples set
171 // to 1.
172 SkASSERT(mipLevelCount > 0);
173 D3D12_RESOURCE_DESC resourceDesc;
174 resourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;
175 // TODO: will use 4MB alignment for MSAA textures and 64KB for everything else
176 // might want to manually set alignment to 4KB for smaller textures
177 resourceDesc.Alignment = 0;
178 resourceDesc.Width = dimensions.fWidth;
179 resourceDesc.Height = dimensions.fHeight;
180 resourceDesc.DepthOrArraySize = 1;
181 resourceDesc.MipLevels = mipLevelCount;
182 resourceDesc.Format = dxgiFormat;
183 resourceDesc.SampleDesc.Count = 1;
184 resourceDesc.SampleDesc.Quality = 0; // quality levels are only supported for tiled resources
185 // so ignore for now
186 resourceDesc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; // use driver-selected swizzle for now
187 resourceDesc.Flags = usageFlags;
188
189 GrMipMapsStatus mipMapsStatus =
190 mipLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated;
191
192 sk_sp<GrD3DTexture> tex;
193 if (renderable == GrRenderable::kYes) {
194 tex = GrD3DTextureRenderTarget::MakeNewTextureRenderTarget(
195 this, budgeted, dimensions, renderTargetSampleCnt, resourceDesc, isProtected,
196 mipMapsStatus);
197 } else {
198 tex = GrD3DTexture::MakeNewTexture(this, budgeted, dimensions, resourceDesc, isProtected,
199 mipMapsStatus);
200 }
201
202 if (!tex) {
203 return nullptr;
204 }
205
206 if (levelClearMask) {
207 // TODO
208 }
209 return std::move(tex);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500210}
211
212sk_sp<GrTexture> GrD3DGpu::onCreateCompressedTexture(SkISize dimensions,
213 const GrBackendFormat& format,
214 SkBudgeted budgeted,
215 GrMipMapped mipMapped,
216 GrProtected isProtected,
217 const void* data, size_t dataSize) {
218 // TODO
219 return nullptr;
220}
221
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400222static bool check_resource_info(const GrD3DTextureResourceInfo& info) {
Jim Van Verth9aa9a682020-04-01 10:13:48 -0400223 if (!info.fResource.get()) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400224 return false;
225 }
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400226 return true;
227}
228
229static bool check_tex_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info) {
230 if (!caps.isFormatTexturable(info.fFormat)) {
231 return false;
232 }
233 return true;
234}
235
236static bool check_rt_resource_info(const GrD3DCaps& caps, const GrD3DTextureResourceInfo& info,
237 int sampleCnt) {
238 if (!caps.isFormatRenderable(info.fFormat, sampleCnt)) {
239 return false;
240 }
241 return true;
242}
243
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400244sk_sp<GrTexture> GrD3DGpu::onWrapBackendTexture(const GrBackendTexture& tex,
245 GrWrapOwnership,
246 GrWrapCacheable wrapType,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400247 GrIOType ioType) {
248 GrD3DTextureResourceInfo textureInfo;
249 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
250 return nullptr;
251 }
252
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400253 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400254 return nullptr;
255 }
256
257 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
258 return nullptr;
259 }
260
261 // TODO: support protected context
262 if (tex.isProtected()) {
263 return nullptr;
264 }
265
266 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
267 SkASSERT(state);
268 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, ioType, textureInfo,
269 std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500270}
271
272sk_sp<GrTexture> GrD3DGpu::onWrapCompressedBackendTexture(const GrBackendTexture& tex,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400273 GrWrapOwnership,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500274 GrWrapCacheable wrapType) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400275 GrD3DTextureResourceInfo textureInfo;
276 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
277 return nullptr;
278 }
279
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400280 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400281 return nullptr;
282 }
283
284 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
285 return nullptr;
286 }
287
288 // TODO: support protected context
289 if (tex.isProtected()) {
290 return nullptr;
291 }
292
293 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
294 SkASSERT(state);
295 return GrD3DTexture::MakeWrappedTexture(this, tex.dimensions(), wrapType, kRead_GrIOType,
296 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500297}
298
299sk_sp<GrTexture> GrD3DGpu::onWrapRenderableBackendTexture(const GrBackendTexture& tex,
300 int sampleCnt,
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500301 GrWrapOwnership ownership,
302 GrWrapCacheable cacheable) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400303 GrD3DTextureResourceInfo textureInfo;
304 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
305 return nullptr;
306 }
307
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400308 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400309 return nullptr;
310 }
311
312 if (!check_tex_resource_info(this->d3dCaps(), textureInfo)) {
313 return nullptr;
314 }
315 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
316 return nullptr;
317 }
318
319 // TODO: support protected context
320 if (tex.isProtected()) {
321 return nullptr;
322 }
323
324 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
325
326 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
327 SkASSERT(state);
328
329 return GrD3DTextureRenderTarget::MakeWrappedTextureRenderTarget(this, tex.dimensions(),
330 sampleCnt, cacheable,
331 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500332}
333
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400334sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& rt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400335 // Currently the Direct3D backend does not support wrapping of msaa render targets directly. In
336 // general this is not an issue since swapchain images in D3D are never multisampled. Thus if
337 // you want a multisampled RT it is best to wrap the swapchain images and then let Skia handle
338 // creating and owning the MSAA images.
339 if (rt.sampleCnt() > 1) {
340 return nullptr;
341 }
342
343 GrD3DTextureResourceInfo info;
344 if (!rt.getD3DTextureResourceInfo(&info)) {
345 return nullptr;
346 }
347
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400348 if (!check_resource_info(info)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400349 return nullptr;
350 }
351
352 if (!check_rt_resource_info(this->d3dCaps(), info, rt.sampleCnt())) {
353 return nullptr;
354 }
355
356 // TODO: support protected context
357 if (rt.isProtected()) {
358 return nullptr;
359 }
360
361 sk_sp<GrD3DResourceState> state = rt.getGrD3DResourceState();
362
363 sk_sp<GrD3DRenderTarget> tgt = GrD3DRenderTarget::MakeWrappedRenderTarget(
364 this, rt.dimensions(), 1, info, std::move(state));
365
366 // We don't allow the client to supply a premade stencil buffer. We always create one if needed.
367 SkASSERT(!rt.stencilBits());
368 if (tgt) {
369 SkASSERT(tgt->canAttemptStencilAttachment());
370 }
371
372 return std::move(tgt);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500373}
374
375sk_sp<GrRenderTarget> GrD3DGpu::onWrapBackendTextureAsRenderTarget(const GrBackendTexture& tex,
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400376 int sampleCnt) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400377
378 GrD3DTextureResourceInfo textureInfo;
379 if (!tex.getD3DTextureResourceInfo(&textureInfo)) {
380 return nullptr;
381 }
Brian Salomon8a78e9c2020-03-27 10:42:15 -0400382 if (!check_resource_info(textureInfo)) {
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400383 return nullptr;
384 }
385
386 if (!check_rt_resource_info(this->d3dCaps(), textureInfo, sampleCnt)) {
387 return nullptr;
388 }
389
390 // TODO: support protected context
391 if (tex.isProtected()) {
392 return nullptr;
393 }
394
395 sampleCnt = this->d3dCaps().getRenderTargetSampleCount(sampleCnt, textureInfo.fFormat);
396 if (!sampleCnt) {
397 return nullptr;
398 }
399
400 sk_sp<GrD3DResourceState> state = tex.getGrD3DResourceState();
401 SkASSERT(state);
402
403 return GrD3DRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt,
404 textureInfo, std::move(state));
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500405}
406
407sk_sp<GrGpuBuffer> GrD3DGpu::onCreateBuffer(size_t sizeInBytes, GrGpuBufferType type,
Jim Van Verthd6ad4802020-04-03 14:59:20 -0400408 GrAccessPattern accessPattern, const void* data) {
409 sk_sp<GrD3DBuffer> buffer = GrD3DBuffer::Make(this, sizeInBytes, type, accessPattern);
410 if (data && buffer) {
411 buffer->updateData(data, sizeInBytes);
412 }
413
414 return std::move(buffer);
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500415}
416
417GrStencilAttachment* GrD3DGpu::createStencilAttachmentForRenderTarget(
418 const GrRenderTarget* rt, int width, int height, int numStencilSamples) {
419 // TODO
420 return nullptr;
421}
422
423GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400424 const GrBackendFormat& format,
425 GrRenderable,
426 GrMipMapped mipMapped,
427 GrProtected,
428 const BackendTextureData*) {
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500429 // TODO
430 return GrBackendTexture();
431}
432
433GrBackendTexture GrD3DGpu::onCreateCompressedBackendTexture(SkISize dimensions,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400434 const GrBackendFormat& format,
435 GrMipMapped mipMapped,
436 GrProtected,
437 const BackendTextureData*) {
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500438 // TODO
439 return GrBackendTexture();
440}
441
442void GrD3DGpu::deleteBackendTexture(const GrBackendTexture& tex) {
443 // TODO
444}
445
Robert Phillips979b2232020-02-20 10:47:29 -0500446bool GrD3DGpu::compile(const GrProgramDesc&, const GrProgramInfo&) {
447 return false;
448}
449
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500450#if GR_TEST_UTILS
451bool GrD3DGpu::isTestingOnlyBackendTexture(const GrBackendTexture& tex) const {
452 // TODO
453 return false;
454}
455
456GrBackendRenderTarget GrD3DGpu::createTestingOnlyBackendRenderTarget(int w, int h,
Jim Van Verthaa90dad2020-03-30 15:00:39 -0400457 GrColorType colorType) {
Jim Van Verthd2d4c5e2020-02-19 14:57:58 -0500458 // TODO
459 return GrBackendRenderTarget();
460}
461
462void GrD3DGpu::deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) {}
463#endif