blob: 8b7a065478ba064b83c8107602ac9f43560ec14f [file] [log] [blame]
reed@google.com5d4ba882012-07-31 15:45:27 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
bsalomonafe30052015-01-16 07:32:33 -08008#include "SkSurface_Gpu.h"
9
Greg Daniel7ef28f32017-04-20 16:41:55 +000010#include "GrBackendSurface.h"
robertphillips15c42ca2016-08-04 08:45:02 -070011#include "GrContextPriv.h"
Robert Phillips2890fbf2017-07-26 15:48:41 -040012#include "GrRenderTarget.h"
Robert Phillips0ae6faa2017-03-21 16:22:00 -040013#include "GrRenderTargetContextPriv.h"
Robert Phillips646e4292017-06-13 12:44:56 -040014#include "GrTexture.h"
Robert Phillips0ae6faa2017-03-21 16:22:00 -040015
reed@google.com5d4ba882012-07-31 15:45:27 +000016#include "SkCanvas.h"
Brian Osman47299142017-03-07 13:22:22 -050017#include "SkColorSpace_Base.h"
Robert Phillipsad8a43f2017-08-30 12:06:35 -040018#include "SkDeferredDisplayList.h"
robertphillips@google.com97b6b072012-10-31 14:48:39 +000019#include "SkGpuDevice.h"
bsalomonafe30052015-01-16 07:32:33 -080020#include "SkImage_Base.h"
reed8b26b992015-05-07 15:36:17 -070021#include "SkImage_Gpu.h"
bsalomonafe30052015-01-16 07:32:33 -080022#include "SkImagePriv.h"
23#include "SkSurface_Base.h"
Robert Phillipsad8a43f2017-08-30 12:06:35 -040024#include "SkSurfaceCharacterization.h"
reed@google.com5d4ba882012-07-31 15:45:27 +000025
reedf037e0b2014-10-30 11:34:15 -070026#if SK_SUPPORT_GPU
27
robertphillips24e91282016-04-29 06:46:36 -070028SkSurface_Gpu::SkSurface_Gpu(sk_sp<SkGpuDevice> device)
bsalomonafe30052015-01-16 07:32:33 -080029 : INHERITED(device->width(), device->height(), &device->surfaceProps())
robertphillips24e91282016-04-29 06:46:36 -070030 , fDevice(std::move(device)) {
Robert Phillips0ae6faa2017-03-21 16:22:00 -040031 SkASSERT(fDevice->accessRenderTargetContext()->asSurfaceProxy()->priv().isExact());
robertphillips@google.com97b6b072012-10-31 14:48:39 +000032}
reed@google.com5d4ba882012-07-31 15:45:27 +000033
robertphillips@google.com97b6b072012-10-31 14:48:39 +000034SkSurface_Gpu::~SkSurface_Gpu() {
reed@google.com5d4ba882012-07-31 15:45:27 +000035}
36
joshualitt81793412015-07-08 12:54:04 -070037static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface,
38 SkSurface::BackendHandleAccess access) {
reedfa5e68e2015-06-29 07:37:01 -070039 switch (access) {
joshualitt81793412015-07-08 12:54:04 -070040 case SkSurface::kFlushRead_BackendHandleAccess:
reedfa5e68e2015-06-29 07:37:01 -070041 break;
joshualitt81793412015-07-08 12:54:04 -070042 case SkSurface::kFlushWrite_BackendHandleAccess:
43 case SkSurface::kDiscardWrite_BackendHandleAccess:
reed884200e2015-06-29 09:00:20 -070044 // for now we don't special-case on Discard, but we may in the future.
joshualitt81793412015-07-08 12:54:04 -070045 surface->notifyContentWillChange(SkSurface::kRetain_ContentChangeMode);
reedfa5e68e2015-06-29 07:37:01 -070046 break;
reedfa5e68e2015-06-29 07:37:01 -070047 }
fmalitae2639082015-08-06 07:04:51 -070048
49 // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in.
robertphillipsea70c4b2016-07-20 08:54:31 -070050 surface->getDevice()->flush();
Brian Osman11052242016-10-27 14:47:55 -040051 GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext();
52 return rtc->accessRenderTarget();
joshualitt81793412015-07-08 12:54:04 -070053}
54
55GrBackendObject SkSurface_Gpu::onGetTextureHandle(BackendHandleAccess access) {
56 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
Robert Phillips833dcf42016-11-18 08:44:13 -050057 if (!rt) {
58 return 0;
59 }
joshualitt81793412015-07-08 12:54:04 -070060 GrTexture* texture = rt->asTexture();
61 if (texture) {
62 return texture->getTextureHandle();
63 }
64 return 0;
65}
66
67bool SkSurface_Gpu::onGetRenderTargetHandle(GrBackendObject* obj, BackendHandleAccess access) {
68 GrRenderTarget* rt = prepare_rt_for_external_access(this, access);
Robert Phillips833dcf42016-11-18 08:44:13 -050069 if (!rt) {
70 return false;
71 }
joshualitt81793412015-07-08 12:54:04 -070072 *obj = rt->getRenderTargetHandle();
73 return true;
reedfa5e68e2015-06-29 07:37:01 -070074}
75
reed@google.com5d4ba882012-07-31 15:45:27 +000076SkCanvas* SkSurface_Gpu::onNewCanvas() {
reed4a8126e2014-09-22 07:29:03 -070077 SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags;
bsalomonb5b49742016-02-10 10:41:01 -080078 flags = static_cast<SkCanvas::InitFlags>(flags | SkCanvas::kConservativeRasterClip_InitFlag);
reed4a8126e2014-09-22 07:29:03 -070079
robertphillips24e91282016-04-29 06:46:36 -070080 return new SkCanvas(fDevice.get(), flags);
reed@google.com5d4ba882012-07-31 15:45:27 +000081}
82
reede8f30622016-03-23 18:59:25 -070083sk_sp<SkSurface> SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
Brian Osman11052242016-10-27 14:47:55 -040084 int sampleCount = fDevice->accessRenderTargetContext()->numColorSamples();
85 GrSurfaceOrigin origin = fDevice->accessRenderTargetContext()->origin();
bsalomonafe30052015-01-16 07:32:33 -080086 // TODO: Make caller specify this (change virtual signature of onNewSurface).
bsalomon5ec26ae2016-02-25 08:33:02 -080087 static const SkBudgeted kBudgeted = SkBudgeted::kNo;
reede8f30622016-03-23 18:59:25 -070088 return SkSurface::MakeRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
robertphillips7e922762016-07-26 11:38:17 -070089 origin, &this->props());
reed@google.com5d4ba882012-07-31 15:45:27 +000090}
91
Robert Phillipsac6b1fa2017-03-20 08:38:50 -040092sk_sp<SkImage> SkSurface_Gpu::onNewImageSnapshot() {
Robert Phillipse2f7d182016-12-15 09:23:05 -050093 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
94 if (!rtc) {
Robert Phillipse60ad622016-11-17 10:22:48 -050095 return nullptr;
96 }
97
Robert Phillipse2f7d182016-12-15 09:23:05 -050098 GrContext* ctx = fDevice->context();
99
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400100 if (!rtc->asSurfaceProxy()) {
101 return nullptr;
102 }
103
104 SkBudgeted budgeted = rtc->asSurfaceProxy()->isBudgeted();
105
106 sk_sp<GrTextureProxy> srcProxy = rtc->asTextureProxyRef();
bsalomonb2c01332016-02-26 10:37:26 -0800107 // If the original render target is a buffer originally created by the client, then we don't
108 // want to ever retarget the SkSurface at another buffer we create. Force a copy now to avoid
109 // copy-on-write.
Mike Reed7eb01f82016-12-30 06:23:12 -0500110 if (!srcProxy || rtc->priv().refsWrappedObjects()) {
Robert Phillips81dd3e02017-06-23 11:59:24 -0400111 SkASSERT(rtc->origin() == rtc->asSurfaceProxy()->origin());
Robert Phillipse2f7d182016-12-15 09:23:05 -0500112
Greg Daniel65c7f662017-10-30 13:39:09 -0400113 // TODO: We should look at the rtc to see if it is mipped and if so create the copy as well
114 // with mips.
115 srcProxy = GrSurfaceProxy::Copy(ctx, rtc->asSurfaceProxy(), GrMipMapped::kNo, budgeted);
bsalomonf47b9a32016-02-22 11:02:58 -0800116 }
Robert Phillipse2f7d182016-12-15 09:23:05 -0500117
reed8b26b992015-05-07 15:36:17 -0700118 const SkImageInfo info = fDevice->imageInfo();
reede8f30622016-03-23 18:59:25 -0700119 sk_sp<SkImage> image;
Robert Phillips0ae6faa2017-03-21 16:22:00 -0400120 if (srcProxy) {
121 // The renderTargetContext coming out of SkGpuDevice should always be exact and the
122 // above copy creates a kExact surfaceContext.
123 SkASSERT(srcProxy->priv().isExact());
124 image = sk_make_sp<SkImage_Gpu>(ctx, kNeedNewImageUniqueID,
125 info.alphaType(), std::move(srcProxy),
126 info.refColorSpace(), budgeted);
reed8b26b992015-05-07 15:36:17 -0700127 }
reed4af267b2014-11-21 08:46:37 -0800128 return image;
reed@google.com5d4ba882012-07-31 15:45:27 +0000129}
130
kkinnunenabcfab42015-02-22 22:53:44 -0800131// Create a new render target and, if necessary, copy the contents of the old
132// render target into it. Note that this flushes the SkGpuDevice but
robertphillips@google.com97b6b072012-10-31 14:48:39 +0000133// doesn't force an OpenGL flush.
commit-bot@chromium.orgc4c98702013-04-22 14:28:01 +0000134void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
Robert Phillips602b79c2017-06-23 11:26:28 -0400135 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
136
137 // are we sharing our backing proxy with the image? Note this call should never create a new
bsalomoneaaaf0b2015-01-23 08:08:04 -0800138 // image because onCopyOnWrite is only called when there is a cached image.
Robert Phillipsac6b1fa2017-03-20 08:38:50 -0400139 sk_sp<SkImage> image(this->refCachedImage());
bsalomoneaaaf0b2015-01-23 08:08:04 -0800140 SkASSERT(image);
Robert Phillips602b79c2017-06-23 11:26:28 -0400141
142 GrSurfaceProxy* imageProxy = ((SkImage_Base*) image.get())->peekProxy();
143 SkASSERT(imageProxy);
144
145 if (rtc->asSurfaceProxy()->underlyingUniqueID() == imageProxy->underlyingUniqueID()) {
Robert Phillips6de99042017-01-31 11:31:39 -0500146 fDevice->replaceRenderTargetContext(SkSurface::kRetain_ContentChangeMode == mode);
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +0000147 } else if (kDiscard_ContentChangeMode == mode) {
148 this->SkSurface_Gpu::onDiscard();
robertphillips@google.com97b6b072012-10-31 14:48:39 +0000149 }
reed@google.com5d4ba882012-07-31 15:45:27 +0000150}
151
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +0000152void SkSurface_Gpu::onDiscard() {
Brian Osman11052242016-10-27 14:47:55 -0400153 fDevice->accessRenderTargetContext()->discard();
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +0000154}
155
Greg Daniel51316782017-08-02 15:10:09 +0000156GrSemaphoresSubmitted SkSurface_Gpu::onFlush(int numSemaphores,
157 GrBackendSemaphore signalSemaphores[]) {
Greg Danielc64ee462017-06-15 16:59:49 -0400158 return fDevice->flushAndSignalSemaphores(numSemaphores, signalSemaphores);
Greg Daniela5cb7812017-06-16 09:45:32 -0400159}
160
Greg Danielc64ee462017-06-15 16:59:49 -0400161bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) {
162 return fDevice->wait(numSemaphores, waitSemaphores);
ericrkf7b8b8a2016-02-24 14:49:51 -0800163}
164
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400165bool SkSurface_Gpu::onCharacterize(SkSurfaceCharacterization* data) const {
166 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
167
Brian Salomonf3569f02017-10-24 12:52:33 -0400168 data->set(rtc->origin(), rtc->width(), rtc->height(), rtc->colorSpaceInfo().config(),
169 rtc->numColorSamples());
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400170 return true;
171}
172
173bool SkSurface_Gpu::isCompatible(const SkSurfaceCharacterization& data) const {
174 GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext();
175
Brian Salomonf3569f02017-10-24 12:52:33 -0400176 return data.origin() == rtc->origin() && data.width() == rtc->width() &&
177 data.height() == rtc->height() && data.config() == rtc->colorSpaceInfo().config() &&
Robert Phillipsad8a43f2017-08-30 12:06:35 -0400178 data.sampleCount() == rtc->numColorSamples();
179}
180
181void SkSurface_Gpu::onDraw(SkDeferredDisplayList* dl) {
182 if (!this->isCompatible(dl->characterization())) {
183 return;
184 }
185
186 // Ultimately need to pass opLists from the DeferredDisplayList on to the
187 // SkGpuDevice's renderTargetContext.
188 dl->draw(this);
189}
190
191
reed@google.com5d4ba882012-07-31 15:45:27 +0000192///////////////////////////////////////////////////////////////////////////////
193
brianosman0e22eb82016-08-30 07:07:59 -0700194bool SkSurface_Gpu::Valid(const SkImageInfo& info) {
195 switch (info.colorType()) {
196 case kRGBA_F16_SkColorType:
Stan Iliev4ed9ae42017-07-25 11:59:12 -0400197 return (!info.colorSpace()) || info.colorSpace()->gammaIsLinear();
brianosman0e22eb82016-08-30 07:07:59 -0700198 case kRGBA_8888_SkColorType:
199 case kBGRA_8888_SkColorType:
200 return !info.colorSpace() || info.colorSpace()->gammaCloseToSRGB();
201 default:
202 return !info.colorSpace();
203 }
204}
205
206bool SkSurface_Gpu::Valid(GrContext* context, GrPixelConfig config, SkColorSpace* colorSpace) {
207 switch (config) {
208 case kRGBA_half_GrPixelConfig:
Stan Iliev4ed9ae42017-07-25 11:59:12 -0400209 return (!colorSpace) || colorSpace->gammaIsLinear();
brianosman0e22eb82016-08-30 07:07:59 -0700210 case kSRGBA_8888_GrPixelConfig:
211 case kSBGRA_8888_GrPixelConfig:
Matt Sarettf3880932017-03-24 10:06:03 -0400212 return context->caps()->srgbSupport() && colorSpace && colorSpace->gammaCloseToSRGB();
brianosman0e22eb82016-08-30 07:07:59 -0700213 case kRGBA_8888_GrPixelConfig:
214 case kBGRA_8888_GrPixelConfig:
215 // If we don't have sRGB support, we may get here with a color space. It still needs
216 // to be sRGB-like (so that the application will work correctly on sRGB devices.)
217 return !colorSpace ||
Matt Sarettf3880932017-03-24 10:06:03 -0400218 (colorSpace->gammaCloseToSRGB() && !context->caps()->srgbSupport());
brianosman0e22eb82016-08-30 07:07:59 -0700219 default:
220 return !colorSpace;
221 }
222}
223
reede8f30622016-03-23 18:59:25 -0700224sk_sp<SkSurface> SkSurface::MakeRenderTarget(GrContext* ctx, SkBudgeted budgeted,
225 const SkImageInfo& info, int sampleCount,
Greg Daniele252f082017-10-23 16:05:23 -0400226 GrSurfaceOrigin origin, const SkSurfaceProps* props,
227 bool shouldCreateWithMips) {
Greg Danielf47069c2017-10-24 11:57:01 -0400228 if (!ctx) {
229 return nullptr;
230 }
brianosman0e22eb82016-08-30 07:07:59 -0700231 if (!SkSurface_Gpu::Valid(info)) {
232 return nullptr;
233 }
234
Greg Daniele252f082017-10-23 16:05:23 -0400235 GrMipMapped mipMapped = shouldCreateWithMips ? GrMipMapped::kYes : GrMipMapped::kNo;
236
Greg Danielf47069c2017-10-24 11:57:01 -0400237 if (!ctx->caps()->mipMapSupport()) {
238 mipMapped = GrMipMapped::kNo;
239 }
240
robertphillips24e91282016-04-29 06:46:36 -0700241 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(
Greg Daniele252f082017-10-23 16:05:23 -0400242 ctx, budgeted, info, sampleCount, origin, props, mipMapped,
243 SkGpuDevice::kClear_InitContents));
bsalomonafe30052015-01-16 07:32:33 -0800244 if (!device) {
halcanary96fcdcc2015-08-27 07:41:13 -0700245 return nullptr;
reed@google.com5d4ba882012-07-31 15:45:27 +0000246 }
robertphillips24e91282016-04-29 06:46:36 -0700247 return sk_make_sp<SkSurface_Gpu>(std::move(device));
reed@google.com5d4ba882012-07-31 15:45:27 +0000248}
reedf037e0b2014-10-30 11:34:15 -0700249
Greg Daniel7ef28f32017-04-20 16:41:55 +0000250sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& tex,
251 GrSurfaceOrigin origin, int sampleCnt,
252 sk_sp<SkColorSpace> colorSpace,
253 const SkSurfaceProps* props) {
254 if (!context) {
halcanary96fcdcc2015-08-27 07:41:13 -0700255 return nullptr;
bsalomone4579ad2015-04-08 08:38:40 -0700256 }
Greg Daniel7ef28f32017-04-20 16:41:55 +0000257 if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) {
brianosman0e22eb82016-08-30 07:07:59 -0700258 return nullptr;
259 }
robertphillips15c42ca2016-08-04 08:45:02 -0700260
Brian Osman11052242016-10-27 14:47:55 -0400261 sk_sp<GrRenderTargetContext> rtc(context->contextPriv().makeBackendTextureRenderTargetContext(
Greg Daniel7ef28f32017-04-20 16:41:55 +0000262 tex,
263 origin,
264 sampleCnt,
robertphillips15c42ca2016-08-04 08:45:02 -0700265 std::move(colorSpace),
Brian Osmanc1e37052017-03-09 14:19:20 -0500266 props));
Brian Osman11052242016-10-27 14:47:55 -0400267 if (!rtc) {
halcanary96fcdcc2015-08-27 07:41:13 -0700268 return nullptr;
bsalomone4579ad2015-04-08 08:38:40 -0700269 }
robertphillips15c42ca2016-08-04 08:45:02 -0700270
Greg Daniel7ef28f32017-04-20 16:41:55 +0000271 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
robertphillips24e91282016-04-29 06:46:36 -0700272 SkGpuDevice::kUninit_InitContents));
bsalomone4579ad2015-04-08 08:38:40 -0700273 if (!device) {
halcanary96fcdcc2015-08-27 07:41:13 -0700274 return nullptr;
bsalomone4579ad2015-04-08 08:38:40 -0700275 }
robertphillips24e91282016-04-29 06:46:36 -0700276 return sk_make_sp<SkSurface_Gpu>(std::move(device));
bsalomone4579ad2015-04-08 08:38:40 -0700277}
278
reede8f30622016-03-23 18:59:25 -0700279sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context,
Greg Danielbcf612b2017-05-01 13:50:58 +0000280 const GrBackendRenderTarget& backendRT,
281 GrSurfaceOrigin origin,
282 sk_sp<SkColorSpace> colorSpace,
283 const SkSurfaceProps* props) {
284 if (!context) {
285 return nullptr;
286 }
287 if (!SkSurface_Gpu::Valid(context, backendRT.config(), colorSpace.get())) {
brianosman0e22eb82016-08-30 07:07:59 -0700288 return nullptr;
289 }
robertphillips15c42ca2016-08-04 08:45:02 -0700290
Brian Osman11052242016-10-27 14:47:55 -0400291 sk_sp<GrRenderTargetContext> rtc(
Greg Danielbcf612b2017-05-01 13:50:58 +0000292 context->contextPriv().makeBackendRenderTargetRenderTargetContext(backendRT,
293 origin,
Brian Osman11052242016-10-27 14:47:55 -0400294 std::move(colorSpace),
295 props));
296 if (!rtc) {
halcanary96fcdcc2015-08-27 07:41:13 -0700297 return nullptr;
bsalomond3e259a2015-06-30 12:04:40 -0700298 }
robertphillips15c42ca2016-08-04 08:45:02 -0700299
Greg Danielbcf612b2017-05-01 13:50:58 +0000300 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc),
301 backendRT.width(), backendRT.height(),
robertphillips24e91282016-04-29 06:46:36 -0700302 SkGpuDevice::kUninit_InitContents));
bsalomond3e259a2015-06-30 12:04:40 -0700303 if (!device) {
halcanary96fcdcc2015-08-27 07:41:13 -0700304 return nullptr;
bsalomond3e259a2015-06-30 12:04:40 -0700305 }
robertphillips15c42ca2016-08-04 08:45:02 -0700306
robertphillips24e91282016-04-29 06:46:36 -0700307 return sk_make_sp<SkSurface_Gpu>(std::move(device));
bsalomond3e259a2015-06-30 12:04:40 -0700308}
309
reede8f30622016-03-23 18:59:25 -0700310sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context,
Greg Daniel7ef28f32017-04-20 16:41:55 +0000311 const GrBackendTexture& tex,
312 GrSurfaceOrigin origin,
313 int sampleCnt,
314 sk_sp<SkColorSpace> colorSpace,
315 const SkSurfaceProps* props) {
316 if (!context) {
317 return nullptr;
318 }
319 if (!SkSurface_Gpu::Valid(context, tex.config(), colorSpace.get())) {
brianosman0e22eb82016-08-30 07:07:59 -0700320 return nullptr;
321 }
robertphillips15c42ca2016-08-04 08:45:02 -0700322
Brian Osman11052242016-10-27 14:47:55 -0400323 sk_sp<GrRenderTargetContext> rtc(
324 context->contextPriv().makeBackendTextureAsRenderTargetRenderTargetContext(
Greg Daniel7ef28f32017-04-20 16:41:55 +0000325 tex,
326 origin,
327 sampleCnt,
Brian Osman11052242016-10-27 14:47:55 -0400328 std::move(colorSpace),
329 props));
330 if (!rtc) {
ericrkf7b8b8a2016-02-24 14:49:51 -0800331 return nullptr;
332 }
robertphillips15c42ca2016-08-04 08:45:02 -0700333
Greg Daniel7ef28f32017-04-20 16:41:55 +0000334 sk_sp<SkGpuDevice> device(SkGpuDevice::Make(context, std::move(rtc), tex.width(), tex.height(),
robertphillips24e91282016-04-29 06:46:36 -0700335 SkGpuDevice::kUninit_InitContents));
ericrkf7b8b8a2016-02-24 14:49:51 -0800336 if (!device) {
337 return nullptr;
338 }
robertphillips24e91282016-04-29 06:46:36 -0700339 return sk_make_sp<SkSurface_Gpu>(std::move(device));
ericrkf7b8b8a2016-02-24 14:49:51 -0800340}
341
reedf037e0b2014-10-30 11:34:15 -0700342#endif