1/**********************************************************
2 * Copyright 2009-2015 VMware, Inc.  All rights reserved.
3 *
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:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
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
22 * SOFTWARE.
23 *
24 **********************************************************/
25
26/**
27 * @file
28 * This file implements the SVGA interface into this winsys, defined
29 * in drivers/svga/svga_winsys.h.
30 *
31 * @author Keith Whitwell
32 * @author Jose Fonseca
33 */
34
35#include <libsync.h>
36
37#include "svga_cmd.h"
38#include "svga3d_caps.h"
39
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_msg.h"
52#include "vmw_shader.h"
53#include "vmw_query.h"
54#include "svga3d_surfacedefs.h"
55
56/**
57 * Try to get a surface backing buffer from the cache
58 * if it's this size or smaller.
59 */
60#define VMW_TRY_CACHED_SIZE (2*1024*1024)
61
62static struct svga_winsys_buffer *
63vmw_svga_winsys_buffer_create(struct svga_winsys_screen *sws,
64                              unsigned alignment,
65                              unsigned usage,
66                              unsigned size)
67{
68   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
69   struct vmw_buffer_desc desc;
70   struct pb_manager *provider;
71   struct pb_buffer *buffer;
72
73   memset(&desc, 0, sizeof desc);
74   desc.pb_desc.alignment = alignment;
75   desc.pb_desc.usage = usage;
76
77   if (usage == SVGA_BUFFER_USAGE_PINNED) {
78      if (vws->pools.query_fenced == NULL && !vmw_query_pools_init(vws))
79	 return NULL;
80      provider = vws->pools.query_fenced;
81   } else if (usage == SVGA_BUFFER_USAGE_SHADER) {
82      provider = vws->pools.mob_shader_slab_fenced;
83   } else
84      provider = vws->pools.gmr_fenced;
85
86   assert(provider);
87   buffer = provider->create_buffer(provider, size, &desc.pb_desc);
88
89   if(!buffer && provider == vws->pools.gmr_fenced) {
90
91      assert(provider);
92      provider = vws->pools.gmr_slab_fenced;
93      buffer = provider->create_buffer(provider, size, &desc.pb_desc);
94   }
95
96   if (!buffer)
97      return NULL;
98
99   return vmw_svga_winsys_buffer_wrap(buffer);
100}
101
102
103static void
104vmw_svga_winsys_fence_reference(struct svga_winsys_screen *sws,
105                                struct pipe_fence_handle **pdst,
106                                struct pipe_fence_handle *src)
107{
108    struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
109
110    vmw_fence_reference(vws, pdst, src);
111}
112
113
114static int
115vmw_svga_winsys_fence_signalled(struct svga_winsys_screen *sws,
116                                struct pipe_fence_handle *fence,
117                                unsigned flag)
118{
119   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
120
121   return vmw_fence_signalled(vws, fence, flag);
122}
123
124
125static int
126vmw_svga_winsys_fence_finish(struct svga_winsys_screen *sws,
127                             struct pipe_fence_handle *fence,
128                             uint64_t timeout,
129                             unsigned flag)
130{
131   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
132
133   return vmw_fence_finish(vws, fence, timeout, flag);
134}
135
136
137static int
138vmw_svga_winsys_fence_get_fd(struct svga_winsys_screen *sws,
139                             struct pipe_fence_handle *fence,
140                             boolean duplicate)
141{
142   if (duplicate)
143      return dup(vmw_fence_get_fd(fence));
144   else
145      return vmw_fence_get_fd(fence);
146}
147
148
149static void
150vmw_svga_winsys_fence_create_fd(struct svga_winsys_screen *sws,
151                                struct pipe_fence_handle **fence,
152                                int32_t fd)
153{
154   *fence = vmw_fence_create(NULL, 0, 0, 0, dup(fd));
155}
156
157static int
158vmw_svga_winsys_fence_server_sync(struct svga_winsys_screen *sws,
159                                  int32_t *context_fd,
160                                  struct pipe_fence_handle *fence)
161{
162   int32_t fd = sws->fence_get_fd(sws, fence, FALSE);
163
164   /* If we don't have fd, we don't need to merge fd into the context's fd. */
165   if (fd == -1)
166      return 0;
167
168   return sync_accumulate("vmwgfx", context_fd, fd);
169}
170
171
172static struct svga_winsys_surface *
173vmw_svga_winsys_surface_create(struct svga_winsys_screen *sws,
174                               SVGA3dSurfaceAllFlags flags,
175                               SVGA3dSurfaceFormat format,
176                               unsigned usage,
177                               SVGA3dSize size,
178                               uint32 numLayers,
179                               uint32 numMipLevels,
180                               unsigned sampleCount)
181{
182   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
183   struct vmw_svga_winsys_surface *surface;
184   struct vmw_buffer_desc desc;
185   struct pb_manager *provider;
186   uint32_t buffer_size;
187   uint32_t num_samples = 1;
188   SVGA3dMSPattern multisample_pattern = SVGA3D_MS_PATTERN_NONE;
189   SVGA3dMSQualityLevel quality_level = SVGA3D_MS_QUALITY_NONE;
190
191   memset(&desc, 0, sizeof(desc));
192   surface = CALLOC_STRUCT(vmw_svga_winsys_surface);
193   if(!surface)
194      goto no_surface;
195
196   pipe_reference_init(&surface->refcnt, 1);
197   p_atomic_set(&surface->validated, 0);
198   surface->screen = vws;
199   (void) mtx_init(&surface->mutex, mtx_plain);
200   surface->shared = !!(usage & SVGA_SURFACE_USAGE_SHARED);
201   provider = (surface->shared) ? vws->pools.gmr : vws->pools.mob_fenced;
202
203   /*
204    * When multisampling is not supported sample count received is 0,
205    * otherwise should have a valid sample count.
206    */
207   if ((flags & SVGA3D_SURFACE_MULTISAMPLE) != 0) {
208      if (sampleCount == 0)
209         goto no_sid;
210      num_samples = sampleCount;
211      multisample_pattern = SVGA3D_MS_PATTERN_STANDARD;
212      quality_level = SVGA3D_MS_QUALITY_FULL;
213   }
214
215   /*
216    * Used for the backing buffer GB surfaces, and to approximate
217    * when to flush on non-GB hosts.
218    */
219   buffer_size = svga3dsurface_get_serialized_size_extended(format, size,
220                                                            numMipLevels,
221                                                            numLayers,
222                                                            num_samples);
223   if (flags & SVGA3D_SURFACE_BIND_STREAM_OUTPUT)
224      buffer_size += sizeof(SVGA3dDXSOState);
225
226   if (buffer_size > vws->ioctl.max_texture_size) {
227      goto no_sid;
228   }
229
230   if (sws->have_gb_objects) {
231      SVGAGuestPtr ptr = {0,0};
232
233      /*
234       * If the backing buffer size is small enough, try to allocate a
235       * buffer out of the buffer cache. Otherwise, let the kernel allocate
236       * a suitable buffer for us.
237       */
238      if (buffer_size < VMW_TRY_CACHED_SIZE && !surface->shared) {
239         struct pb_buffer *pb_buf;
240
241         surface->size = buffer_size;
242         desc.pb_desc.alignment = 4096;
243         desc.pb_desc.usage = 0;
244         pb_buf = provider->create_buffer(provider, buffer_size, &desc.pb_desc);
245         surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
246         if (surface->buf && !vmw_gmr_bufmgr_region_ptr(pb_buf, &ptr))
247            assert(0);
248      }
249
250      surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
251                                                 size, numLayers,
252                                                 numMipLevels, sampleCount,
253                                                 ptr.gmrId,
254                                                 multisample_pattern,
255                                                 quality_level,
256                                                 surface->buf ? NULL :
257                                                 &desc.region);
258
259      if (surface->sid == SVGA3D_INVALID_ID) {
260         if (surface->buf == NULL) {
261            goto no_sid;
262         } else {
263            /*
264             * Kernel refused to allocate a surface for us.
265             * Perhaps something was wrong with our buffer?
266             * This is really a guard against future new size requirements
267             * on the backing buffers.
268             */
269            vmw_svga_winsys_buffer_destroy(sws, surface->buf);
270            surface->buf = NULL;
271            surface->sid = vmw_ioctl_gb_surface_create(vws, flags, format, usage,
272                                                       size, numLayers,
273                                                       numMipLevels, sampleCount,
274                                                       0, multisample_pattern,
275                                                       quality_level,
276                                                       &desc.region);
277            if (surface->sid == SVGA3D_INVALID_ID)
278               goto no_sid;
279         }
280      }
281
282      /*
283       * If the kernel created the buffer for us, wrap it into a
284       * vmw_svga_winsys_buffer.
285       */
286      if (surface->buf == NULL) {
287         struct pb_buffer *pb_buf;
288
289         surface->size = vmw_region_size(desc.region);
290         desc.pb_desc.alignment = 4096;
291         desc.pb_desc.usage = VMW_BUFFER_USAGE_SHARED;
292         pb_buf = provider->create_buffer(provider, surface->size,
293                                          &desc.pb_desc);
294         surface->buf = vmw_svga_winsys_buffer_wrap(pb_buf);
295         if (surface->buf == NULL) {
296            vmw_ioctl_region_destroy(desc.region);
297            vmw_ioctl_surface_destroy(vws, surface->sid);
298            goto no_sid;
299         }
300      }
301   } else {
302      /* Legacy surface only support 32-bit svga3d flags */
303      surface->sid = vmw_ioctl_surface_create(vws, (SVGA3dSurface1Flags)flags,
304                                              format, usage, size, numLayers,
305                                              numMipLevels, sampleCount);
306      if(surface->sid == SVGA3D_INVALID_ID)
307         goto no_sid;
308
309      /* Best estimate for surface size, used for early flushing. */
310      surface->size = buffer_size;
311      surface->buf = NULL;
312   }
313
314   return svga_winsys_surface(surface);
315
316no_sid:
317   if (surface->buf)
318      vmw_svga_winsys_buffer_destroy(sws, surface->buf);
319
320   FREE(surface);
321no_surface:
322   return NULL;
323}
324
325static boolean
326vmw_svga_winsys_surface_can_create(struct svga_winsys_screen *sws,
327                               SVGA3dSurfaceFormat format,
328                               SVGA3dSize size,
329                               uint32 numLayers,
330                               uint32 numMipLevels,
331                               uint32 numSamples)
332{
333   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
334   uint32_t buffer_size;
335
336   buffer_size = svga3dsurface_get_serialized_size(format, size,
337                                                   numMipLevels,
338                                                   numLayers);
339   if (numSamples > 1)
340      buffer_size *= numSamples;
341
342   if (buffer_size > vws->ioctl.max_texture_size) {
343	return FALSE;
344   }
345   return TRUE;
346}
347
348
349static boolean
350vmw_svga_winsys_surface_is_flushed(struct svga_winsys_screen *sws,
351                                   struct svga_winsys_surface *surface)
352{
353   struct vmw_svga_winsys_surface *vsurf = vmw_svga_winsys_surface(surface);
354   return (p_atomic_read(&vsurf->validated) == 0);
355}
356
357
358static void
359vmw_svga_winsys_surface_ref(struct svga_winsys_screen *sws,
360			    struct svga_winsys_surface **pDst,
361			    struct svga_winsys_surface *src)
362{
363   struct vmw_svga_winsys_surface *d_vsurf = vmw_svga_winsys_surface(*pDst);
364   struct vmw_svga_winsys_surface *s_vsurf = vmw_svga_winsys_surface(src);
365
366   vmw_svga_winsys_surface_reference(&d_vsurf, s_vsurf);
367   *pDst = svga_winsys_surface(d_vsurf);
368}
369
370
371static void
372vmw_svga_winsys_destroy(struct svga_winsys_screen *sws)
373{
374   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
375
376   vmw_winsys_destroy(vws);
377}
378
379
380static SVGA3dHardwareVersion
381vmw_svga_winsys_get_hw_version(struct svga_winsys_screen *sws)
382{
383   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
384
385   if (sws->have_gb_objects)
386      return SVGA3D_HWVERSION_WS8_B1;
387
388   return (SVGA3dHardwareVersion) vws->ioctl.hwversion;
389}
390
391
392static boolean
393vmw_svga_winsys_get_cap(struct svga_winsys_screen *sws,
394                        SVGA3dDevCapIndex index,
395                        SVGA3dDevCapResult *result)
396{
397   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
398
399   if (index > vws->ioctl.num_cap_3d ||
400       index >= SVGA3D_DEVCAP_MAX ||
401       !vws->ioctl.cap_3d[index].has_cap)
402      return FALSE;
403
404   *result = vws->ioctl.cap_3d[index].result;
405   return TRUE;
406}
407
408struct svga_winsys_gb_shader *
409vmw_svga_winsys_shader_create(struct svga_winsys_screen *sws,
410			      SVGA3dShaderType type,
411			      const uint32 *bytecode,
412			      uint32 bytecodeLen)
413{
414   struct vmw_winsys_screen *vws = vmw_winsys_screen(sws);
415   struct vmw_svga_winsys_shader *shader;
416   void *code;
417
418   shader = CALLOC_STRUCT(vmw_svga_winsys_shader);
419   if(!shader)
420      goto out_no_shader;
421
422   pipe_reference_init(&shader->refcnt, 1);
423   p_atomic_set(&shader->validated, 0);
424   shader->screen = vws;
425   shader->buf = vmw_svga_winsys_buffer_create(sws, 64,
426					       SVGA_BUFFER_USAGE_SHADER,
427					       bytecodeLen);
428   if (!shader->buf)
429      goto out_no_buf;
430
431   code = vmw_svga_winsys_buffer_map(sws, shader->buf, PIPE_TRANSFER_WRITE);
432   if (!code)
433      goto out_no_buf;
434
435   memcpy(code, bytecode, bytecodeLen);
436   vmw_svga_winsys_buffer_unmap(sws, shader->buf);
437
438   if (!sws->have_vgpu10) {
439      shader->shid = vmw_ioctl_shader_create(vws, type, bytecodeLen);
440      if (shader->shid == SVGA3D_INVALID_ID)
441         goto out_no_shid;
442   }
443
444   return svga_winsys_shader(shader);
445
446out_no_shid:
447   vmw_svga_winsys_buffer_destroy(sws, shader->buf);
448out_no_buf:
449   FREE(shader);
450out_no_shader:
451   return NULL;
452}
453
454void
455vmw_svga_winsys_shader_destroy(struct svga_winsys_screen *sws,
456			       struct svga_winsys_gb_shader *shader)
457{
458   struct vmw_svga_winsys_shader *d_shader =
459      vmw_svga_winsys_shader(shader);
460
461   vmw_svga_winsys_shader_reference(&d_shader, NULL);
462}
463
464static void
465vmw_svga_winsys_stats_inc(enum svga_stats_count index)
466{
467}
468
469static void
470vmw_svga_winsys_stats_time_push(enum svga_stats_time index,
471                                struct svga_winsys_stats_timeframe *tf)
472{
473}
474
475static void
476vmw_svga_winsys_stats_time_pop()
477{
478}
479
480boolean
481vmw_winsys_screen_init_svga(struct vmw_winsys_screen *vws)
482{
483   vws->base.destroy = vmw_svga_winsys_destroy;
484   vws->base.get_hw_version = vmw_svga_winsys_get_hw_version;
485   vws->base.get_cap = vmw_svga_winsys_get_cap;
486   vws->base.context_create = vmw_svga_winsys_context_create;
487   vws->base.surface_create = vmw_svga_winsys_surface_create;
488   vws->base.surface_is_flushed = vmw_svga_winsys_surface_is_flushed;
489   vws->base.surface_reference = vmw_svga_winsys_surface_ref;
490   vws->base.surface_can_create = vmw_svga_winsys_surface_can_create;
491   vws->base.buffer_create = vmw_svga_winsys_buffer_create;
492   vws->base.buffer_map = vmw_svga_winsys_buffer_map;
493   vws->base.buffer_unmap = vmw_svga_winsys_buffer_unmap;
494   vws->base.buffer_destroy = vmw_svga_winsys_buffer_destroy;
495   vws->base.fence_reference = vmw_svga_winsys_fence_reference;
496   vws->base.fence_signalled = vmw_svga_winsys_fence_signalled;
497   vws->base.shader_create = vmw_svga_winsys_shader_create;
498   vws->base.shader_destroy = vmw_svga_winsys_shader_destroy;
499   vws->base.fence_finish = vmw_svga_winsys_fence_finish;
500   vws->base.fence_get_fd = vmw_svga_winsys_fence_get_fd;
501   vws->base.fence_create_fd = vmw_svga_winsys_fence_create_fd;
502   vws->base.fence_server_sync = vmw_svga_winsys_fence_server_sync;
503
504   vws->base.query_create = vmw_svga_winsys_query_create;
505   vws->base.query_init = vmw_svga_winsys_query_init;
506   vws->base.query_destroy = vmw_svga_winsys_query_destroy;
507   vws->base.query_get_result = vmw_svga_winsys_query_get_result;
508
509   vws->base.stats_inc = vmw_svga_winsys_stats_inc;
510   vws->base.stats_time_push = vmw_svga_winsys_stats_time_push;
511   vws->base.stats_time_pop = vmw_svga_winsys_stats_time_pop;
512
513   vws->base.host_log = vmw_svga_winsys_host_log;
514
515   return TRUE;
516}
517
518
519