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