1/**************************************************************************
2 *
3 * Copyright 2009, VMware, Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27/*
28 * Author: Keith Whitwell <keithw@vmware.com>
29 * Author: Jakob Bornecrantz <wallbraker@gmail.com>
30 */
31
32#include "dri_screen.h"
33#include "dri_context.h"
34#include "dri_drawable.h"
35
36#include "pipe/p_screen.h"
37#include "util/format/u_format.h"
38#include "util/u_memory.h"
39#include "util/u_inlines.h"
40
41static uint32_t drifb_ID = 0;
42
43static bool
44dri_st_framebuffer_validate(struct st_context_iface *stctx,
45                            struct st_framebuffer_iface *stfbi,
46                            const enum st_attachment_type *statts,
47                            unsigned count,
48                            struct pipe_resource **out)
49{
50   struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
51   struct dri_drawable *drawable =
52      (struct dri_drawable *) stfbi->st_manager_private;
53   struct dri_screen *screen = dri_screen(drawable->sPriv);
54   unsigned statt_mask, new_mask;
55   bool new_stamp;
56   int i;
57   unsigned int lastStamp;
58   struct pipe_resource **textures =
59      drawable->stvis.samples > 1 ? drawable->msaa_textures
60                                  : drawable->textures;
61
62   statt_mask = 0x0;
63   for (i = 0; i < count; i++)
64      statt_mask |= (1 << statts[i]);
65
66   /* record newly allocated textures */
67   new_mask = (statt_mask & ~drawable->texture_mask);
68
69   /*
70    * dPriv->dri2.stamp is the server stamp.  dPriv->lastStamp is the
71    * client stamp.  It has the value of the server stamp when last
72    * checked.
73    */
74   do {
75      lastStamp = drawable->dPriv->lastStamp;
76      new_stamp = (drawable->texture_stamp != lastStamp);
77
78      if (new_stamp || new_mask) {
79         if (new_stamp && drawable->update_drawable_info)
80            drawable->update_drawable_info(drawable);
81
82         drawable->allocate_textures(ctx, drawable, statts, count);
83
84         /* add existing textures */
85         for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
86            if (textures[i])
87               statt_mask |= (1 << i);
88         }
89
90         drawable->texture_stamp = lastStamp;
91         drawable->texture_mask = statt_mask;
92      }
93   } while (lastStamp != drawable->dPriv->lastStamp);
94
95   /* Flush the pending set_damage_region request. */
96   struct pipe_screen *pscreen = screen->base.screen;
97
98   if (new_mask & (1 << ST_ATTACHMENT_BACK_LEFT) &&
99       pscreen->set_damage_region) {
100      struct pipe_resource *resource = textures[ST_ATTACHMENT_BACK_LEFT];
101
102      pscreen->set_damage_region(pscreen, resource,
103                                 drawable->num_damage_rects,
104                                 drawable->damage_rects);
105   }
106
107   if (!out)
108      return true;
109
110   /* Set the window-system buffers for the gallium frontend. */
111   for (i = 0; i < count; i++)
112      pipe_resource_reference(&out[i], textures[statts[i]]);
113
114   return true;
115}
116
117static bool
118dri_st_framebuffer_flush_front(struct st_context_iface *stctx,
119                               struct st_framebuffer_iface *stfbi,
120                               enum st_attachment_type statt)
121{
122   struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
123   struct dri_drawable *drawable =
124      (struct dri_drawable *) stfbi->st_manager_private;
125
126   /* XXX remove this and just set the correct one on the framebuffer */
127   return drawable->flush_frontbuffer(ctx, drawable, statt);
128}
129
130/**
131 * The gallium frontend framebuffer interface flush_swapbuffers callback
132 */
133static bool
134dri_st_framebuffer_flush_swapbuffers(struct st_context_iface *stctx,
135                                     struct st_framebuffer_iface *stfbi)
136{
137   struct dri_context *ctx = (struct dri_context *)stctx->st_manager_private;
138   struct dri_drawable *drawable =
139      (struct dri_drawable *) stfbi->st_manager_private;
140
141   if (drawable->flush_swapbuffers)
142      drawable->flush_swapbuffers(ctx, drawable);
143
144   return true;
145}
146
147/**
148 * This is called when we need to set up GL rendering to a new X window.
149 */
150bool
151dri_create_buffer(__DRIscreen * sPriv,
152		  __DRIdrawable * dPriv,
153		  const struct gl_config * visual, bool isPixmap)
154{
155   struct dri_screen *screen = sPriv->driverPrivate;
156   struct dri_drawable *drawable = NULL;
157
158   if (isPixmap)
159      goto fail;		       /* not implemented */
160
161   drawable = CALLOC_STRUCT(dri_drawable);
162   if (drawable == NULL)
163      goto fail;
164
165   dri_fill_st_visual(&drawable->stvis, screen, visual);
166
167   /* setup the st_framebuffer_iface */
168   drawable->base.visual = &drawable->stvis;
169   drawable->base.flush_front = dri_st_framebuffer_flush_front;
170   drawable->base.validate = dri_st_framebuffer_validate;
171   drawable->base.flush_swapbuffers = dri_st_framebuffer_flush_swapbuffers;
172   drawable->base.st_manager_private = (void *) drawable;
173
174   drawable->screen = screen;
175   drawable->sPriv = sPriv;
176   drawable->dPriv = dPriv;
177
178   dPriv->driverPrivate = (void *)drawable;
179   p_atomic_set(&drawable->base.stamp, 1);
180   drawable->base.ID = p_atomic_inc_return(&drifb_ID);
181   drawable->base.state_manager = &screen->base;
182
183   return true;
184fail:
185   FREE(drawable);
186   return false;
187}
188
189void
190dri_destroy_buffer(__DRIdrawable * dPriv)
191{
192   struct dri_drawable *drawable = dri_drawable(dPriv);
193   struct dri_screen *screen = drawable->screen;
194   struct st_api *stapi = screen->st_api;
195   int i;
196
197   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
198      pipe_resource_reference(&drawable->textures[i], NULL);
199   for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
200      pipe_resource_reference(&drawable->msaa_textures[i], NULL);
201
202   screen->base.screen->fence_reference(screen->base.screen,
203         &drawable->throttle_fence, NULL);
204
205   /* Notify the st manager that this drawable is no longer valid */
206   stapi->destroy_drawable(stapi, &drawable->base);
207
208   FREE(drawable->damage_rects);
209   FREE(drawable);
210}
211
212/**
213 * Validate the texture at an attachment.  Allocate the texture if it does not
214 * exist.  Used by the TFP extension.
215 */
216static void
217dri_drawable_validate_att(struct dri_context *ctx,
218                          struct dri_drawable *drawable,
219                          enum st_attachment_type statt)
220{
221   enum st_attachment_type statts[ST_ATTACHMENT_COUNT];
222   unsigned i, count = 0;
223
224   /* check if buffer already exists */
225   if (drawable->texture_mask & (1 << statt))
226      return;
227
228   /* make sure DRI2 does not destroy existing buffers */
229   for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
230      if (drawable->texture_mask & (1 << i)) {
231         statts[count++] = i;
232      }
233   }
234   statts[count++] = statt;
235
236   drawable->texture_stamp = drawable->dPriv->lastStamp - 1;
237
238   drawable->base.validate(ctx->st, &drawable->base, statts, count, NULL);
239}
240
241/**
242 * These are used for GLX_EXT_texture_from_pixmap
243 */
244static void
245dri_set_tex_buffer2(__DRIcontext *pDRICtx, GLint target,
246                    GLint format, __DRIdrawable *dPriv)
247{
248   struct dri_context *ctx = dri_context(pDRICtx);
249   struct st_context_iface *st = ctx->st;
250   struct dri_drawable *drawable = dri_drawable(dPriv);
251   struct pipe_resource *pt;
252
253   if (st->thread_finish)
254      st->thread_finish(st);
255
256   dri_drawable_validate_att(ctx, drawable, ST_ATTACHMENT_FRONT_LEFT);
257
258   /* Use the pipe resource associated with the X drawable */
259   pt = drawable->textures[ST_ATTACHMENT_FRONT_LEFT];
260
261   if (pt) {
262      enum pipe_format internal_format = pt->format;
263
264      if (format == __DRI_TEXTURE_FORMAT_RGB)  {
265         /* only need to cover the formats recognized by dri_fill_st_visual */
266         switch (internal_format) {
267         case PIPE_FORMAT_R16G16B16A16_FLOAT:
268            internal_format = PIPE_FORMAT_R16G16B16X16_FLOAT;
269            break;
270         case PIPE_FORMAT_B10G10R10A2_UNORM:
271            internal_format = PIPE_FORMAT_B10G10R10X2_UNORM;
272            break;
273         case PIPE_FORMAT_R10G10B10A2_UNORM:
274            internal_format = PIPE_FORMAT_R10G10B10X2_UNORM;
275            break;
276         case PIPE_FORMAT_BGRA8888_UNORM:
277            internal_format = PIPE_FORMAT_BGRX8888_UNORM;
278            break;
279         case PIPE_FORMAT_ARGB8888_UNORM:
280            internal_format = PIPE_FORMAT_XRGB8888_UNORM;
281            break;
282         default:
283            break;
284         }
285      }
286
287      drawable->update_tex_buffer(drawable, ctx, pt);
288
289      ctx->st->teximage(ctx->st,
290            (target == GL_TEXTURE_2D) ? ST_TEXTURE_2D : ST_TEXTURE_RECT,
291            0, internal_format, pt, false);
292   }
293}
294
295static void
296dri_set_tex_buffer(__DRIcontext *pDRICtx, GLint target,
297                   __DRIdrawable *dPriv)
298{
299   dri_set_tex_buffer2(pDRICtx, target, __DRI_TEXTURE_FORMAT_RGBA, dPriv);
300}
301
302const __DRItexBufferExtension driTexBufferExtension = {
303   .base = { __DRI_TEX_BUFFER, 2 },
304
305   .setTexBuffer       = dri_set_tex_buffer,
306   .setTexBuffer2      = dri_set_tex_buffer2,
307   .releaseTexBuffer   = NULL,
308};
309
310/**
311 * Get the format and binding of an attachment.
312 */
313void
314dri_drawable_get_format(struct dri_drawable *drawable,
315                        enum st_attachment_type statt,
316                        enum pipe_format *format,
317                        unsigned *bind)
318{
319   switch (statt) {
320   case ST_ATTACHMENT_FRONT_LEFT:
321   case ST_ATTACHMENT_BACK_LEFT:
322   case ST_ATTACHMENT_FRONT_RIGHT:
323   case ST_ATTACHMENT_BACK_RIGHT:
324      /* Other pieces of the driver stack get confused and behave incorrectly
325       * when they get an sRGB drawable. st/mesa receives "drawable->stvis"
326       * though other means and handles it correctly, so we don't really need
327       * to use an sRGB format here.
328       */
329      *format = util_format_linear(drawable->stvis.color_format);
330      *bind = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
331      break;
332   case ST_ATTACHMENT_DEPTH_STENCIL:
333      *format = drawable->stvis.depth_stencil_format;
334      *bind = PIPE_BIND_DEPTH_STENCIL; /* XXX sampler? */
335      break;
336   default:
337      *format = PIPE_FORMAT_NONE;
338      *bind = 0;
339      break;
340   }
341}
342
343void
344dri_pipe_blit(struct pipe_context *pipe,
345              struct pipe_resource *dst,
346              struct pipe_resource *src)
347{
348   struct pipe_blit_info blit;
349
350   if (!dst || !src)
351      return;
352
353   /* From the GL spec, version 4.2, section 4.1.11 (Additional Multisample
354    *  Fragment Operations):
355    *
356    *      If a framebuffer object is not bound, after all operations have
357    *      been completed on the multisample buffer, the sample values for
358    *      each color in the multisample buffer are combined to produce a
359    *      single color value, and that value is written into the
360    *      corresponding color buffers selected by DrawBuffer or
361    *      DrawBuffers. An implementation may defer the writing of the color
362    *      buffers until a later time, but the state of the framebuffer must
363    *      behave as if the color buffers were updated as each fragment was
364    *      processed. The method of combination is not specified. If the
365    *      framebuffer contains sRGB values, then it is recommended that the
366    *      an average of sample values is computed in a linearized space, as
367    *      for blending (see section 4.1.7).
368    *
369    * In other words, to do a resolve operation in a linear space, we have
370    * to set sRGB formats if the original resources were sRGB, so don't use
371    * util_format_linear.
372    */
373
374   memset(&blit, 0, sizeof(blit));
375   blit.dst.resource = dst;
376   blit.dst.box.width = dst->width0;
377   blit.dst.box.height = dst->height0;
378   blit.dst.box.depth = 1;
379   blit.dst.format = dst->format;
380   blit.src.resource = src;
381   blit.src.box.width = src->width0;
382   blit.src.box.height = src->height0;
383   blit.src.box.depth = 1;
384   blit.src.format = src->format;
385   blit.mask = PIPE_MASK_RGBA;
386   blit.filter = PIPE_TEX_FILTER_NEAREST;
387
388   pipe->blit(pipe, &blit);
389}
390
391static void
392dri_postprocessing(struct dri_context *ctx,
393                   struct dri_drawable *drawable,
394                   enum st_attachment_type att)
395{
396   struct pipe_resource *src = drawable->textures[att];
397   struct pipe_resource *zsbuf = drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL];
398
399   if (ctx->pp && src)
400      pp_run(ctx->pp, src, src, zsbuf);
401}
402
403struct notify_before_flush_cb_args {
404   struct dri_context *ctx;
405   struct dri_drawable *drawable;
406   unsigned flags;
407   enum __DRI2throttleReason reason;
408   bool swap_msaa_buffers;
409};
410
411static void
412notify_before_flush_cb(void* _args)
413{
414   struct notify_before_flush_cb_args *args = (struct notify_before_flush_cb_args *) _args;
415   struct st_context_iface *st = args->ctx->st;
416   struct pipe_context *pipe = st->pipe;
417
418   if (args->drawable->stvis.samples > 1 &&
419       (args->reason == __DRI2_THROTTLE_SWAPBUFFER ||
420        args->reason == __DRI2_THROTTLE_COPYSUBBUFFER)) {
421      /* Resolve the MSAA back buffer. */
422      dri_pipe_blit(st->pipe,
423                    args->drawable->textures[ST_ATTACHMENT_BACK_LEFT],
424                    args->drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]);
425
426      if (args->reason == __DRI2_THROTTLE_SWAPBUFFER &&
427          args->drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] &&
428          args->drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT]) {
429         args->swap_msaa_buffers = true;
430      }
431
432      /* FRONT_LEFT is resolved in drawable->flush_frontbuffer. */
433   }
434
435   dri_postprocessing(args->ctx, args->drawable, ST_ATTACHMENT_BACK_LEFT);
436
437   if (pipe->invalidate_resource &&
438       (args->flags & __DRI2_FLUSH_INVALIDATE_ANCILLARY)) {
439      if (args->drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL])
440         pipe->invalidate_resource(pipe, args->drawable->textures[ST_ATTACHMENT_DEPTH_STENCIL]);
441      if (args->drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL])
442         pipe->invalidate_resource(pipe, args->drawable->msaa_textures[ST_ATTACHMENT_DEPTH_STENCIL]);
443   }
444
445   if (args->ctx->hud) {
446      hud_run(args->ctx->hud, args->ctx->st->cso_context,
447              args->drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
448   }
449
450   pipe->flush_resource(pipe, args->drawable->textures[ST_ATTACHMENT_BACK_LEFT]);
451}
452
453/**
454 * DRI2 flush extension, the flush_with_flags function.
455 *
456 * \param context           the context
457 * \param drawable          the drawable to flush
458 * \param flags             a combination of _DRI2_FLUSH_xxx flags
459 * \param throttle_reason   the reason for throttling, 0 = no throttling
460 */
461void
462dri_flush(__DRIcontext *cPriv,
463          __DRIdrawable *dPriv,
464          unsigned flags,
465          enum __DRI2throttleReason reason)
466{
467   struct dri_context *ctx = dri_context(cPriv);
468   struct dri_drawable *drawable = dri_drawable(dPriv);
469   struct st_context_iface *st;
470   unsigned flush_flags;
471   struct notify_before_flush_cb_args args = { 0 };
472
473   if (!ctx) {
474      assert(0);
475      return;
476   }
477
478   st = ctx->st;
479   if (st->thread_finish)
480      st->thread_finish(st);
481
482   if (drawable) {
483      /* prevent recursion */
484      if (drawable->flushing)
485         return;
486
487      drawable->flushing = true;
488   }
489   else {
490      flags &= ~__DRI2_FLUSH_DRAWABLE;
491   }
492
493   if ((flags & __DRI2_FLUSH_DRAWABLE) &&
494       drawable->textures[ST_ATTACHMENT_BACK_LEFT]) {
495      /* We can't do operations on the back buffer here, because there
496       * may be some pending operations that will get flushed by the
497       * call to st->flush (eg: FLUSH_VERTICES).
498       * Instead we register a callback to be notified when all operations
499       * have been submitted but before the call to st_flush.
500       */
501      args.ctx = ctx;
502      args.drawable = drawable;
503      args.flags = flags;
504      args.reason = reason;
505   }
506
507   flush_flags = 0;
508   if (flags & __DRI2_FLUSH_CONTEXT)
509      flush_flags |= ST_FLUSH_FRONT;
510   if (reason == __DRI2_THROTTLE_SWAPBUFFER)
511      flush_flags |= ST_FLUSH_END_OF_FRAME;
512
513   /* Flush the context and throttle if needed. */
514   if (dri_screen(ctx->sPriv)->throttle &&
515       drawable &&
516       (reason == __DRI2_THROTTLE_SWAPBUFFER ||
517        reason == __DRI2_THROTTLE_FLUSHFRONT)) {
518
519      struct pipe_screen *screen = drawable->screen->base.screen;
520      struct pipe_fence_handle *new_fence = NULL;
521
522      st->flush(st, flush_flags, &new_fence, args.ctx ? notify_before_flush_cb : NULL, &args);
523
524      /* throttle on the previous fence */
525      if (drawable->throttle_fence) {
526         screen->fence_finish(screen, NULL, drawable->throttle_fence, PIPE_TIMEOUT_INFINITE);
527         screen->fence_reference(screen, &drawable->throttle_fence, NULL);
528      }
529      drawable->throttle_fence = new_fence;
530   }
531   else if (flags & (__DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT)) {
532      st->flush(st, flush_flags, NULL, args.ctx ? notify_before_flush_cb : NULL, &args);
533   }
534
535   if (drawable) {
536      drawable->flushing = false;
537   }
538
539   /* Swap the MSAA front and back buffers, so that reading
540    * from the front buffer after SwapBuffers returns what was
541    * in the back buffer.
542    */
543   if (args.swap_msaa_buffers) {
544      struct pipe_resource *tmp =
545         drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT];
546
547      drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT] =
548         drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT];
549      drawable->msaa_textures[ST_ATTACHMENT_BACK_LEFT] = tmp;
550
551      /* Now that we have swapped the buffers, this tells the gallium
552       * frontend to revalidate the framebuffer.
553       */
554      p_atomic_inc(&drawable->base.stamp);
555   }
556}
557
558/**
559 * dri_throttle - A DRI2ThrottleExtension throttling function.
560 */
561static void
562dri_throttle(__DRIcontext *cPriv, __DRIdrawable *dPriv,
563             enum __DRI2throttleReason reason)
564{
565   dri_flush(cPriv, dPriv, 0, reason);
566}
567
568
569const __DRI2throttleExtension dri2ThrottleExtension = {
570    .base = { __DRI2_THROTTLE, 1 },
571
572    .throttle          = dri_throttle,
573};
574
575
576/* vim: set sw=3 ts=8 sts=3 expandtab: */
577