1 /**********************************************************
2 * Copyright 2009-2015 VMware, Inc. All rights reserved.
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 **********************************************************/
28 * This file implements the SVGA interface into this winsys, defined
29 * in drivers/svga/svga_winsys.h.
31 * @author Keith Whitwell
32 * @author Jose Fonseca
38 #include "svga3d_caps.h"
40 #include "util/u_inlines.h"
41 #include "util/u_math.h"
42 #include "util/u_memory.h"
43 #include "pipebuffer/pb_buffer.h"
44 #include "pipebuffer/pb_bufmgr.h"
45 #include "svga_winsys.h"
46 #include "vmw_context.h"
47 #include "vmw_screen.h"
48 #include "vmw_surface.h"
49 #include "vmw_buffer.h"
50 #include "vmw_fence.h"
51 #include "vmw_shader.h"
52 #include "vmw_query.h"
53 #include "svga3d_surfacedefs.h"
56 * Try to get a surface backing buffer from the cache
57 * if it's this size or smaller.
59 #define VMW_TRY_CACHED_SIZE (2*1024*1024)
61 static struct svga_winsys_buffer
*
62 vmw_svga_winsys_buffer_create(struct svga_winsys_screen
*sws
,
67 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
68 struct vmw_buffer_desc desc
;
69 struct pb_manager
*provider
;
70 struct pb_buffer
*buffer
;
72 memset(&desc
, 0, sizeof desc
);
73 desc
.pb_desc
.alignment
= alignment
;
74 desc
.pb_desc
.usage
= usage
;
76 if (usage
== SVGA_BUFFER_USAGE_PINNED
) {
77 if (vws
->pools
.query_fenced
== NULL
&& !vmw_query_pools_init(vws
))
79 provider
= vws
->pools
.query_fenced
;
80 } else if (usage
== SVGA_BUFFER_USAGE_SHADER
) {
81 provider
= vws
->pools
.mob_shader_slab_fenced
;
83 provider
= vws
->pools
.gmr_fenced
;
86 buffer
= provider
->create_buffer(provider
, size
, &desc
.pb_desc
);
88 if(!buffer
&& provider
== vws
->pools
.gmr_fenced
) {
91 provider
= vws
->pools
.gmr_slab_fenced
;
92 buffer
= provider
->create_buffer(provider
, size
, &desc
.pb_desc
);
98 return vmw_svga_winsys_buffer_wrap(buffer
);
103 vmw_svga_winsys_fence_reference(struct svga_winsys_screen
*sws
,
104 struct pipe_fence_handle
**pdst
,
105 struct pipe_fence_handle
*src
)
107 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
109 vmw_fence_reference(vws
, pdst
, src
);
114 vmw_svga_winsys_fence_signalled(struct svga_winsys_screen
*sws
,
115 struct pipe_fence_handle
*fence
,
118 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
120 return vmw_fence_signalled(vws
, fence
, flag
);
125 vmw_svga_winsys_fence_finish(struct svga_winsys_screen
*sws
,
126 struct pipe_fence_handle
*fence
,
130 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
132 return vmw_fence_finish(vws
, fence
, timeout
, flag
);
137 vmw_svga_winsys_fence_get_fd(struct svga_winsys_screen
*sws
,
138 struct pipe_fence_handle
*fence
,
142 return dup(vmw_fence_get_fd(fence
));
144 return vmw_fence_get_fd(fence
);
149 vmw_svga_winsys_fence_create_fd(struct svga_winsys_screen
*sws
,
150 struct pipe_fence_handle
**fence
,
153 *fence
= vmw_fence_create(NULL
, 0, 0, 0, dup(fd
));
157 vmw_svga_winsys_fence_server_sync(struct svga_winsys_screen
*sws
,
159 struct pipe_fence_handle
*fence
)
161 int32_t fd
= sws
->fence_get_fd(sws
, fence
, FALSE
);
163 /* If we don't have fd, we don't need to merge fd into the context's fd. */
167 return sync_accumulate("vmwgfx", context_fd
, fd
);
171 static struct svga_winsys_surface
*
172 vmw_svga_winsys_surface_create(struct svga_winsys_screen
*sws
,
173 SVGA3dSurfaceAllFlags flags
,
174 SVGA3dSurfaceFormat format
,
179 unsigned sampleCount
)
181 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
182 struct vmw_svga_winsys_surface
*surface
;
183 struct vmw_buffer_desc desc
;
184 struct pb_manager
*provider
;
185 uint32_t buffer_size
;
186 uint32_t num_samples
= 1;
187 SVGA3dMSPattern multisample_pattern
= SVGA3D_MS_PATTERN_NONE
;
188 SVGA3dMSQualityLevel quality_level
= SVGA3D_MS_QUALITY_NONE
;
190 memset(&desc
, 0, sizeof(desc
));
191 surface
= CALLOC_STRUCT(vmw_svga_winsys_surface
);
195 pipe_reference_init(&surface
->refcnt
, 1);
196 p_atomic_set(&surface
->validated
, 0);
197 surface
->screen
= vws
;
198 (void) mtx_init(&surface
->mutex
, mtx_plain
);
199 surface
->shared
= !!(usage
& SVGA_SURFACE_USAGE_SHARED
);
200 provider
= (surface
->shared
) ? vws
->pools
.gmr
: vws
->pools
.mob_fenced
;
203 * When multisampling is not supported sample count received is 0,
204 * otherwise should have a valid sample count.
206 if ((flags
& SVGA3D_SURFACE_MULTISAMPLE
) != 0) {
207 if (sampleCount
== 0)
209 num_samples
= sampleCount
;
210 multisample_pattern
= SVGA3D_MS_PATTERN_STANDARD
;
211 quality_level
= SVGA3D_MS_QUALITY_FULL
;
215 * Used for the backing buffer GB surfaces, and to approximate
216 * when to flush on non-GB hosts.
218 buffer_size
= svga3dsurface_get_serialized_size_extended(format
, size
,
222 if (flags
& SVGA3D_SURFACE_BIND_STREAM_OUTPUT
)
223 buffer_size
+= sizeof(SVGA3dDXSOState
);
225 if (buffer_size
> vws
->ioctl
.max_texture_size
) {
229 if (sws
->have_gb_objects
) {
230 SVGAGuestPtr ptr
= {0,0};
233 * If the backing buffer size is small enough, try to allocate a
234 * buffer out of the buffer cache. Otherwise, let the kernel allocate
235 * a suitable buffer for us.
237 if (buffer_size
< VMW_TRY_CACHED_SIZE
&& !surface
->shared
) {
238 struct pb_buffer
*pb_buf
;
240 surface
->size
= buffer_size
;
241 desc
.pb_desc
.alignment
= 4096;
242 desc
.pb_desc
.usage
= 0;
243 pb_buf
= provider
->create_buffer(provider
, buffer_size
, &desc
.pb_desc
);
244 surface
->buf
= vmw_svga_winsys_buffer_wrap(pb_buf
);
245 if (surface
->buf
&& !vmw_gmr_bufmgr_region_ptr(pb_buf
, &ptr
))
249 surface
->sid
= vmw_ioctl_gb_surface_create(vws
, flags
, format
, usage
,
251 numMipLevels
, sampleCount
,
255 surface
->buf
? NULL
:
258 if (surface
->sid
== SVGA3D_INVALID_ID
) {
259 if (surface
->buf
== NULL
) {
263 * Kernel refused to allocate a surface for us.
264 * Perhaps something was wrong with our buffer?
265 * This is really a guard against future new size requirements
266 * on the backing buffers.
268 vmw_svga_winsys_buffer_destroy(sws
, surface
->buf
);
270 surface
->sid
= vmw_ioctl_gb_surface_create(vws
, flags
, format
, usage
,
272 numMipLevels
, sampleCount
,
273 0, multisample_pattern
,
276 if (surface
->sid
== SVGA3D_INVALID_ID
)
282 * If the kernel created the buffer for us, wrap it into a
283 * vmw_svga_winsys_buffer.
285 if (surface
->buf
== NULL
) {
286 struct pb_buffer
*pb_buf
;
288 surface
->size
= vmw_region_size(desc
.region
);
289 desc
.pb_desc
.alignment
= 4096;
290 desc
.pb_desc
.usage
= VMW_BUFFER_USAGE_SHARED
;
291 pb_buf
= provider
->create_buffer(provider
, surface
->size
,
293 surface
->buf
= vmw_svga_winsys_buffer_wrap(pb_buf
);
294 if (surface
->buf
== NULL
) {
295 vmw_ioctl_region_destroy(desc
.region
);
296 vmw_ioctl_surface_destroy(vws
, surface
->sid
);
301 /* Legacy surface only support 32-bit svga3d flags */
302 surface
->sid
= vmw_ioctl_surface_create(vws
, (SVGA3dSurface1Flags
)flags
,
303 format
, usage
, size
, numLayers
,
304 numMipLevels
, sampleCount
);
305 if(surface
->sid
== SVGA3D_INVALID_ID
)
308 /* Best estimate for surface size, used for early flushing. */
309 surface
->size
= buffer_size
;
313 return svga_winsys_surface(surface
);
317 vmw_svga_winsys_buffer_destroy(sws
, surface
->buf
);
325 vmw_svga_winsys_surface_can_create(struct svga_winsys_screen
*sws
,
326 SVGA3dSurfaceFormat format
,
332 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
333 uint32_t buffer_size
;
335 buffer_size
= svga3dsurface_get_serialized_size(format
, size
,
339 buffer_size
*= numSamples
;
341 if (buffer_size
> vws
->ioctl
.max_texture_size
) {
349 vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen
*sws
,
350 struct svga_winsys_surface
*surface
)
352 struct vmw_svga_winsys_surface
*vsurf
= vmw_svga_winsys_surface(surface
);
353 return (p_atomic_read(&vsurf
->validated
) == 0);
358 vmw_svga_winsys_surface_ref(struct svga_winsys_screen
*sws
,
359 struct svga_winsys_surface
**pDst
,
360 struct svga_winsys_surface
*src
)
362 struct vmw_svga_winsys_surface
*d_vsurf
= vmw_svga_winsys_surface(*pDst
);
363 struct vmw_svga_winsys_surface
*s_vsurf
= vmw_svga_winsys_surface(src
);
365 vmw_svga_winsys_surface_reference(&d_vsurf
, s_vsurf
);
366 *pDst
= svga_winsys_surface(d_vsurf
);
371 vmw_svga_winsys_destroy(struct svga_winsys_screen
*sws
)
373 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
375 vmw_winsys_destroy(vws
);
379 static SVGA3dHardwareVersion
380 vmw_svga_winsys_get_hw_version(struct svga_winsys_screen
*sws
)
382 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
384 if (sws
->have_gb_objects
)
385 return SVGA3D_HWVERSION_WS8_B1
;
387 return (SVGA3dHardwareVersion
) vws
->ioctl
.hwversion
;
392 vmw_svga_winsys_get_cap(struct svga_winsys_screen
*sws
,
393 SVGA3dDevCapIndex index
,
394 SVGA3dDevCapResult
*result
)
396 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
398 if (index
> vws
->ioctl
.num_cap_3d
||
399 index
>= SVGA3D_DEVCAP_MAX
||
400 !vws
->ioctl
.cap_3d
[index
].has_cap
)
403 *result
= vws
->ioctl
.cap_3d
[index
].result
;
407 struct svga_winsys_gb_shader
*
408 vmw_svga_winsys_shader_create(struct svga_winsys_screen
*sws
,
409 SVGA3dShaderType type
,
410 const uint32
*bytecode
,
413 struct vmw_winsys_screen
*vws
= vmw_winsys_screen(sws
);
414 struct vmw_svga_winsys_shader
*shader
;
417 shader
= CALLOC_STRUCT(vmw_svga_winsys_shader
);
421 pipe_reference_init(&shader
->refcnt
, 1);
422 p_atomic_set(&shader
->validated
, 0);
423 shader
->screen
= vws
;
424 shader
->buf
= vmw_svga_winsys_buffer_create(sws
, 64,
425 SVGA_BUFFER_USAGE_SHADER
,
430 code
= vmw_svga_winsys_buffer_map(sws
, shader
->buf
, PIPE_TRANSFER_WRITE
);
434 memcpy(code
, bytecode
, bytecodeLen
);
435 vmw_svga_winsys_buffer_unmap(sws
, shader
->buf
);
437 if (!sws
->have_vgpu10
) {
438 shader
->shid
= vmw_ioctl_shader_create(vws
, type
, bytecodeLen
);
439 if (shader
->shid
== SVGA3D_INVALID_ID
)
443 return svga_winsys_shader(shader
);
446 vmw_svga_winsys_buffer_destroy(sws
, shader
->buf
);
454 vmw_svga_winsys_shader_destroy(struct svga_winsys_screen
*sws
,
455 struct svga_winsys_gb_shader
*shader
)
457 struct vmw_svga_winsys_shader
*d_shader
=
458 vmw_svga_winsys_shader(shader
);
460 vmw_svga_winsys_shader_reference(&d_shader
, NULL
);
464 vmw_svga_winsys_stats_inc(enum svga_stats_count index
)
469 vmw_svga_winsys_stats_time_push(enum svga_stats_time index
,
470 struct svga_winsys_stats_timeframe
*tf
)
475 vmw_svga_winsys_stats_time_pop()
480 vmw_winsys_screen_init_svga(struct vmw_winsys_screen
*vws
)
482 vws
->base
.destroy
= vmw_svga_winsys_destroy
;
483 vws
->base
.get_hw_version
= vmw_svga_winsys_get_hw_version
;
484 vws
->base
.get_cap
= vmw_svga_winsys_get_cap
;
485 vws
->base
.context_create
= vmw_svga_winsys_context_create
;
486 vws
->base
.surface_create
= vmw_svga_winsys_surface_create
;
487 vws
->base
.surface_is_flushed
= vmw_svga_winsys_surface_is_flushed
;
488 vws
->base
.surface_reference
= vmw_svga_winsys_surface_ref
;
489 vws
->base
.surface_can_create
= vmw_svga_winsys_surface_can_create
;
490 vws
->base
.buffer_create
= vmw_svga_winsys_buffer_create
;
491 vws
->base
.buffer_map
= vmw_svga_winsys_buffer_map
;
492 vws
->base
.buffer_unmap
= vmw_svga_winsys_buffer_unmap
;
493 vws
->base
.buffer_destroy
= vmw_svga_winsys_buffer_destroy
;
494 vws
->base
.fence_reference
= vmw_svga_winsys_fence_reference
;
495 vws
->base
.fence_signalled
= vmw_svga_winsys_fence_signalled
;
496 vws
->base
.shader_create
= vmw_svga_winsys_shader_create
;
497 vws
->base
.shader_destroy
= vmw_svga_winsys_shader_destroy
;
498 vws
->base
.fence_finish
= vmw_svga_winsys_fence_finish
;
499 vws
->base
.fence_get_fd
= vmw_svga_winsys_fence_get_fd
;
500 vws
->base
.fence_create_fd
= vmw_svga_winsys_fence_create_fd
;
501 vws
->base
.fence_server_sync
= vmw_svga_winsys_fence_server_sync
;
503 vws
->base
.query_create
= vmw_svga_winsys_query_create
;
504 vws
->base
.query_init
= vmw_svga_winsys_query_init
;
505 vws
->base
.query_destroy
= vmw_svga_winsys_query_destroy
;
506 vws
->base
.query_get_result
= vmw_svga_winsys_query_get_result
;
508 vws
->base
.stats_inc
= vmw_svga_winsys_stats_inc
;
509 vws
->base
.stats_time_push
= vmw_svga_winsys_stats_time_push
;
510 vws
->base
.stats_time_pop
= vmw_svga_winsys_stats_time_pop
;