1use std::{
2 fmt,
3 ops::{Deref, DerefMut},
4 ptr,
5 time::Duration,
6};
7
8use crate::{
9 gpu::{
10 BackendFormat, BackendRenderTarget, BackendTexture, ContextOptions, FlushInfo,
11 GpuStatsFlags, MutableTextureState, PurgeResourceOptions, RecordingContext,
12 SemaphoresSubmitted, SubmitInfo, SyncCpu,
13 },
14 prelude::*,
15 surfaces, Data, Image, Surface, TextureCompressionType,
16};
17use skia_bindings::{self as sb, GrDirectContext, GrDirectContext_DirectContextID, SkRefCntBase};
18
19#[repr(C)]
20#[derive(Copy, Clone, PartialEq, Eq, Debug)]
21pub struct DirectContextId {
22 id: u32,
23}
24
25native_transmutable!(GrDirectContext_DirectContextID, DirectContextId);
26
27pub type DirectContext = RCHandle<GrDirectContext>;
28
29impl NativeRefCountedBase for GrDirectContext {
30 type Base = SkRefCntBase;
31}
32
33impl Deref for DirectContext {
34 type Target = RecordingContext;
35
36 fn deref(&self) -> &Self::Target {
37 unsafe { transmute_ref(self) }
38 }
39}
40
41impl DerefMut for DirectContext {
42 fn deref_mut(&mut self) -> &mut Self::Target {
43 unsafe { transmute_ref_mut(self) }
44 }
45}
46
47#[derive(Copy, Clone, PartialEq, Eq, Debug)]
48pub struct ResourceCacheLimits {
49 pub max_resources: usize,
50 pub max_resource_bytes: usize,
51}
52
53#[derive(Copy, Clone, PartialEq, Eq, Debug)]
54pub struct ResourceCacheUsage {
55 pub resource_count: usize,
56 pub resource_bytes: usize,
57}
58
59impl fmt::Debug for DirectContext {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 f.debug_struct("DirectContext")
62 .field("base", self as &RecordingContext)
63 .field("resource_cache_limit", &self.resource_cache_limit())
64 .field("resource_cache_usage", &self.resource_cache_usage())
65 .field(
66 "resource_cache_purgeable_bytes",
67 &self.resource_cache_purgeable_bytes(),
68 )
69 .field(
70 "supports_distance_field_text",
71 &self.supports_distance_field_text(),
72 )
73 .finish()
74 }
75}
76
77impl DirectContext {
78 #[cfg(feature = "gl")]
80 #[deprecated(since = "0.74.0", note = "use gpu::direct_contexts::make_gl()")]
81 pub fn new_gl<'a>(
82 interface: impl Into<crate::gpu::gl::Interface>,
83 options: impl Into<Option<&'a ContextOptions>>,
84 ) -> Option<DirectContext> {
85 crate::gpu::direct_contexts::make_gl(interface, options)
86 }
87
88 #[cfg(feature = "vulkan")]
90 #[deprecated(since = "0.74.0", note = "use gpu::direct_contexts::make_vulkan()")]
91 pub fn new_vulkan<'a>(
92 backend_context: &crate::gpu::vk::BackendContext,
93 options: impl Into<Option<&'a ContextOptions>>,
94 ) -> Option<DirectContext> {
95 crate::gpu::direct_contexts::make_vulkan(backend_context, options)
96 }
97
98 #[cfg(feature = "metal")]
99 #[deprecated(since = "0.74.0", note = "use gpu::direct_contexts::make_metal()")]
100 pub fn new_metal<'a>(
101 backend_context: &crate::gpu::mtl::BackendContext,
102 options: impl Into<Option<&'a ContextOptions>>,
103 ) -> Option<DirectContext> {
104 crate::gpu::direct_contexts::make_metal(backend_context, options)
105 }
106
107 #[cfg(feature = "d3d")]
108 #[deprecated(since = "0.95.0", note = "use gpu::direct_contexts::make_d3d()")]
109 #[allow(clippy::missing_safety_doc)]
110 pub unsafe fn new_d3d<'a>(
111 backend_context: &crate::gpu::d3d::BackendContext,
112 options: impl Into<Option<&'a ContextOptions>>,
113 ) -> Option<DirectContext> {
114 crate::gpu::direct_contexts::make_d3d(backend_context, options)
115 }
116
117 pub fn reset(&mut self, backend_state: Option<u32>) -> &mut Self {
118 unsafe {
119 self.native_mut()
120 .resetContext(backend_state.unwrap_or(sb::kAll_GrBackendState))
121 }
122 self
123 }
124
125 pub fn reset_gl_texture_bindings(&mut self) -> &mut Self {
126 unsafe { self.native_mut().resetGLTextureBindings() }
127 self
128 }
129
130 pub fn abandon(&mut self) -> &mut Self {
131 unsafe {
132 sb::GrDirectContext_abandonContext(self.native_mut() as *mut _ as _)
134 }
135 self
136 }
137
138 pub fn is_device_lost(&mut self) -> bool {
139 unsafe { self.native_mut().isDeviceLost() }
140 }
141
142 pub fn oomed(&mut self) -> bool {
145 unsafe { self.native_mut().oomed() }
146 }
147
148 pub fn release_resources_and_abandon(&mut self) -> &mut Self {
149 unsafe {
150 sb::GrDirectContext_releaseResourcesAndAbandonContext(self.native_mut() as *mut _ as _)
151 }
152 self
153 }
154
155 pub fn resource_cache_limit(&self) -> usize {
156 unsafe { self.native().getResourceCacheLimit() }
157 }
158
159 pub fn resource_cache_usage(&self) -> ResourceCacheUsage {
160 let mut resource_count = 0;
161 let mut resource_bytes = 0;
162 unsafe {
163 self.native()
164 .getResourceCacheUsage(&mut resource_count, &mut resource_bytes)
165 }
166 ResourceCacheUsage {
167 resource_count: resource_count.try_into().unwrap(),
168 resource_bytes,
169 }
170 }
171
172 pub fn resource_cache_purgeable_bytes(&self) -> usize {
173 unsafe { self.native().getResourceCachePurgeableBytes() }
174 }
175
176 pub fn set_resource_cache_limits(&mut self, limits: ResourceCacheLimits) {
177 unsafe {
178 self.native_mut().setResourceCacheLimits(
179 limits.max_resources.try_into().unwrap(),
180 limits.max_resource_bytes,
181 )
182 }
183 }
184
185 pub fn set_resource_cache_limit(&mut self, max_resource_bytes: usize) {
186 unsafe { self.native_mut().setResourceCacheLimit(max_resource_bytes) }
187 }
188
189 pub fn free_gpu_resources(&mut self) -> &mut Self {
190 unsafe { sb::GrDirectContext_freeGpuResources(self.native_mut() as *mut _ as _) }
191 self
192 }
193
194 pub fn perform_deferred_cleanup(
195 &mut self,
196 not_used: Duration,
197 opts: impl Into<Option<PurgeResourceOptions>>,
198 ) -> &mut Self {
199 unsafe {
200 sb::C_GrDirectContext_performDeferredCleanup(
201 self.native_mut(),
202 not_used.as_millis().try_into().unwrap(),
203 opts.into().unwrap_or(PurgeResourceOptions::AllResources),
204 )
205 }
206 self
207 }
208
209 pub fn purge_unlocked_resource_bytes(
210 &mut self,
211 bytes_to_purge: usize,
212 prefer_scratch_resources: bool,
213 ) -> &mut Self {
214 unsafe {
215 self.native_mut()
216 .purgeUnlockedResources(bytes_to_purge, prefer_scratch_resources)
217 }
218 self
219 }
220
221 pub fn purge_unlocked_resources(&mut self, opts: PurgeResourceOptions) -> &mut Self {
222 unsafe { self.native_mut().purgeUnlockedResources1(opts) }
223 self
224 }
225
226 pub fn supported_gpu_stats(&self) -> GpuStatsFlags {
227 GpuStatsFlags::from_bits_truncate(unsafe { self.native().supportedGpuStats() })
228 }
229
230 pub fn flush_and_submit(&mut self) -> &mut Self {
233 unsafe { sb::C_GrDirectContext_flushAndSubmit(self.native_mut()) }
234 self
235 }
236
237 pub fn flush_submit_and_sync_cpu(&mut self) -> &mut Self {
238 self.flush(&FlushInfo::default());
239 self.submit(SyncCpu::Yes);
240 self
241 }
242
243 #[deprecated(since = "0.37.0", note = "Use flush()")]
244 pub fn flush_with_info(&mut self, info: &FlushInfo) -> SemaphoresSubmitted {
245 self.flush(info)
246 }
247
248 pub fn flush<'a>(&mut self, info: impl Into<Option<&'a FlushInfo>>) -> SemaphoresSubmitted {
249 let n = self.native_mut();
250 if let Some(info) = info.into() {
251 unsafe { n.flush(info.native()) }
252 } else {
253 let info = FlushInfo::default();
254 unsafe { n.flush(info.native()) }
255 }
256 }
257
258 pub fn flush_image_with_info(
259 &mut self,
260 image: &Image,
261 info: &FlushInfo,
262 ) -> SemaphoresSubmitted {
263 unsafe {
264 sb::C_GrDirectContext_flushImageWithInfo(
265 self.native_mut(),
266 image.clone().into_ptr(),
267 info.native(),
268 )
269 }
270 }
271
272 pub fn flush_image(&mut self, image: &Image) {
273 unsafe { sb::C_GrDirectContext_flushImage(self.native_mut(), image.clone().into_ptr()) }
274 }
275
276 pub fn flush_and_submit_image(&mut self, image: &Image) {
277 unsafe {
278 sb::C_GrDirectContext_flushAndSubmitImage(self.native_mut(), image.clone().into_ptr())
279 }
280 }
281
282 pub fn flush_surface_with_access(
283 &mut self,
284 surface: &mut Surface,
285 access: surfaces::BackendSurfaceAccess,
286 info: &FlushInfo,
287 ) -> SemaphoresSubmitted {
288 unsafe {
289 self.native_mut()
290 .flush3(surface.native_mut(), access, info.native())
291 }
292 }
293
294 pub fn flush_surface_with_texture_state(
295 &mut self,
296 surface: &mut Surface,
297 info: &FlushInfo,
298 new_state: Option<&MutableTextureState>,
299 ) -> SemaphoresSubmitted {
300 unsafe {
301 self.native_mut().flush4(
302 surface.native_mut(),
303 info.native(),
304 new_state.native_ptr_or_null(),
305 )
306 }
307 }
308
309 pub fn flush_and_submit_surface(
310 &mut self,
311 surface: &mut Surface,
312 sync_cpu: impl Into<Option<SyncCpu>>,
313 ) {
314 unsafe {
315 self.native_mut()
316 .flushAndSubmit1(surface.native_mut(), sync_cpu.into().unwrap_or(SyncCpu::No))
317 }
318 }
319
320 pub fn flush_surface(&mut self, surface: &mut Surface) {
321 unsafe { self.native_mut().flush5(surface.native_mut()) }
322 }
323
324 pub fn submit(&mut self, submit_info: impl Into<SubmitInfo>) -> bool {
325 unsafe { self.native_mut().submit(&submit_info.into().into_native()) }
326 }
327
328 pub fn check_async_work_completion(&mut self) {
329 unsafe { self.native_mut().checkAsyncWorkCompletion() }
330 }
331
332 pub fn supports_distance_field_text(&self) -> bool {
335 unsafe { self.native().supportsDistanceFieldText() }
336 }
337}
338
339#[cfg(feature = "vulkan")]
340impl DirectContext {
341 pub fn can_detect_new_vk_pipeline_cache_data(&self) -> bool {
342 unsafe { self.native().canDetectNewVkPipelineCacheData() }
343 }
344
345 pub fn has_new_vk_pipeline_cache_data(&self) -> bool {
346 unsafe { self.native().hasNewVkPipelineCacheData() }
347 }
348
349 pub fn store_vk_pipeline_cache_data(&mut self) -> &mut Self {
350 unsafe {
351 self.native_mut().storeVkPipelineCacheData();
352 }
353 self
354 }
355
356 pub fn store_vk_pipeline_cache_data_with_max_size(&mut self, max_size: usize) -> &mut Self {
357 unsafe {
358 self.native_mut().storeVkPipelineCacheData1(max_size);
359 }
360 self
361 }
362}
363
364impl DirectContext {
365 pub fn compressed_backend_format(&self, compression: TextureCompressionType) -> BackendFormat {
374 let mut backend_format = BackendFormat::new_invalid();
375 unsafe {
376 sb::C_GrDirectContext_compressedBackendFormat(
377 self.native(),
378 compression,
379 backend_format.native_mut(),
380 )
381 };
382 backend_format
383 }
384
385 pub fn set_backend_texture_state(
394 &mut self,
395 backend_texture: &BackendTexture,
396 state: &MutableTextureState,
397 ) -> bool {
398 self.set_backend_texture_state_and_return_previous(backend_texture, state)
399 .is_some()
400 }
401
402 pub fn set_backend_texture_state_and_return_previous(
403 &mut self,
404 backend_texture: &BackendTexture,
405 state: &MutableTextureState,
406 ) -> Option<MutableTextureState> {
407 let mut previous = MutableTextureState::default();
408 unsafe {
409 self.native_mut().setBackendTextureState(
410 backend_texture.native(),
411 state.native(),
412 previous.native_mut(),
413 None,
414 ptr::null_mut(),
415 )
416 }
417 .then_some(previous)
418 }
419
420 pub fn set_backend_render_target_state(
422 &mut self,
423 target: &BackendRenderTarget,
424 state: &MutableTextureState,
425 ) -> bool {
426 self.set_backend_render_target_state_and_return_previous(target, state)
427 .is_some()
428 }
429
430 pub fn set_backend_render_target_state_and_return_previous(
431 &mut self,
432 target: &BackendRenderTarget,
433 state: &MutableTextureState,
434 ) -> Option<MutableTextureState> {
435 let mut previous = MutableTextureState::default();
436 unsafe {
437 self.native_mut().setBackendRenderTargetState(
438 target.native(),
439 state.native(),
440 previous.native_mut(),
441 None,
442 ptr::null_mut(),
443 )
444 }
445 .then_some(previous)
446 }
447
448 pub fn delete_backend_texture(&mut self, texture: &BackendTexture) {
449 unsafe { self.native_mut().deleteBackendTexture(texture.native()) }
450 }
451
452 pub fn precompile_shader(&mut self, key: &Data, data: &Data) -> bool {
453 unsafe {
454 self.native_mut()
455 .precompileShader(key.native(), data.native())
456 }
457 }
458
459 pub fn id(&self) -> DirectContextId {
460 let mut id = DirectContextId { id: 0 };
461 unsafe { sb::C_GrDirectContext_directContextId(self.native(), id.native_mut()) }
462 id
463 }
464}
465
466#[cfg(test)]
467mod tests {
468 use super::DirectContext;
469 use crate::gpu::{SubmitInfo, SyncCpu};
470
471 #[allow(unused)]
472 fn submit_invocation(direct_context: &mut DirectContext) {
473 direct_context.submit(SyncCpu::Yes);
474 direct_context.submit(None);
475 direct_context.submit(Some(SyncCpu::Yes));
476 direct_context.submit(SubmitInfo::default());
477 }
478}