drisw.c revision 1fbfc22d8560c9d900832147f504ff64c64358de
1/**************************************************************************
2 *
3 * Copyright 2009, VMware, Inc.
4 * All Rights Reserved.
5 * Copyright 2010 George Sapountzis <gsapountzis@gmail.com>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sub license, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject to
13 * the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial portions
17 * of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 *
27 **************************************************************************/
28
29/* TODO:
30 *
31 * stride:
32 *
33 * The driver and the loaders (libGL, xserver/glx) compute the stride from the
34 * width independently. winsys has a workaround that works for softpipe but may
35 * explode for other drivers or platforms, rendering- or performance-wise.
36 * Solving this issue properly requires extending the DRISW loader extension,
37 * in order to make the stride available to the putImage callback.
38 *
39 * drisw_api:
40 *
41 * Define drisw_api similarly to dri_api and use it to call the loader. This is
42 * predicated on support for calling the loader from the winsys, which has to
43 * grow for DRI2 as well.
44 *
45 * xshm:
46 *
47 * Allow the loaders to use the XSHM extension. It probably requires callbacks
48 * for createImage/destroyImage similar to DRI2 getBuffers. Probably not worth
49 * it, given the scope of DRISW, unless it falls naturally from properly
50 * solving the above two issues.
51 *
52 * swrast_create_screen:
53 *
54 * Allow for any software renderer to be used. Factor out the code from
55 * targets/libgl-xlib/xlib.c, put it in targets/common or winsys/sw/common and
56 * use it in all software targets.
57 */
58
59#include "util/u_memory.h"
60#include "util/u_inlines.h"
61#include "pipe/p_context.h"
62#include "state_tracker/drm_api.h"
63
64#include "dri_screen.h"
65#include "dri_context.h"
66#include "dri_drawable.h"
67#include "dri_st_api.h"
68#include "dri1_helper.h"
69#include "drisw.h"
70
71
72static INLINE void
73get_drawable_info(__DRIdrawable *dPriv, int *w, int *h)
74{
75   __DRIscreen *sPriv = dPriv->driScreenPriv;
76   const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
77   int x, y;
78
79   loader->getDrawableInfo(dPriv,
80                           &x, &y, w, h,
81                           dPriv->loaderPrivate);
82}
83
84static INLINE void
85put_image(__DRIdrawable *dPriv, void *data)
86{
87   __DRIscreen *sPriv = dPriv->driScreenPriv;
88   const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader;
89
90   loader->putImage(dPriv, __DRI_SWRAST_IMAGE_OP_SWAP,
91                    0, 0, dPriv->w, dPriv->h,
92                    data, dPriv->loaderPrivate);
93}
94
95void
96drisw_update_drawable_info(__DRIdrawable *dPriv)
97{
98   get_drawable_info(dPriv, &dPriv->w, &dPriv->h);
99}
100
101static INLINE void
102drisw_present_texture(__DRIdrawable *dPriv,
103                      struct pipe_texture *ptex)
104{
105   struct dri_drawable *drawable = dri_drawable(dPriv);
106   struct dri_screen *screen = dri_screen(drawable->sPriv);
107   struct pipe_context *pipe;
108   struct pipe_surface *psurf;
109   struct pipe_transfer *ptrans;
110   void *pmap;
111
112   pipe = dri1_get_pipe_context(screen);
113   psurf = dri1_get_pipe_surface(drawable, ptex);
114   if (!pipe || !psurf)
115      return;
116
117   ptrans = pipe->get_tex_transfer(pipe, ptex, 0, 0, 0,
118                                   PIPE_TRANSFER_READ,
119                                   0, 0, dPriv->w, dPriv->h);
120
121   pmap = pipe->transfer_map(pipe, ptrans);
122
123   assert(pmap);
124
125   put_image(dPriv, pmap);
126
127   pipe->transfer_unmap(pipe, ptrans);
128
129   pipe->tex_transfer_destroy(pipe, ptrans);
130}
131
132static INLINE void
133drisw_invalidate_drawable(__DRIdrawable *dPriv)
134{
135   struct dri_context *ctx = dri_get_current();
136   struct dri_drawable *drawable = dri_drawable(dPriv);
137
138   drawable->texture_stamp = dPriv->lastStamp - 1;
139
140   /* check if swapping currently bound buffer */
141   if (ctx && ctx->dPriv == dPriv)
142      ctx->st->notify_invalid_framebuffer(ctx->st, drawable->stfb);
143}
144
145static INLINE void
146drisw_copy_to_front(__DRIdrawable * dPriv,
147                    struct pipe_texture *ptex)
148{
149   drisw_present_texture(dPriv, ptex);
150
151   drisw_invalidate_drawable(dPriv);
152}
153
154/*
155 * Backend functions for st_framebuffer interface and swap_buffers.
156 */
157
158void
159drisw_flush_frontbuffer(struct dri_drawable *drawable,
160                        enum st_attachment_type statt)
161{
162   struct dri_context *ctx = dri_get_current();
163   struct pipe_texture *ptex;
164
165   if (!ctx)
166      return;
167
168   ptex = drawable->textures[statt];
169
170   if (ptex) {
171      drisw_copy_to_front(ctx->dPriv, ptex);
172   }
173}
174
175void
176drisw_swap_buffers(__DRIdrawable *dPriv)
177{
178   struct dri_context *ctx = dri_get_current();
179   struct dri_drawable *drawable = dri_drawable(dPriv);
180   struct pipe_texture *ptex;
181
182   if (!ctx)
183      return;
184
185   ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT];
186
187   if (ptex) {
188      ctx->st->flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
189
190      drisw_copy_to_front(dPriv, ptex);
191   }
192}
193
194/**
195 * Allocate framebuffer attachments.
196 *
197 * During fixed-size operation, the function keeps allocating new attachments
198 * as they are requested. Unused attachments are not removed, not until the
199 * framebuffer is resized or destroyed.
200 *
201 * It should be possible for DRI1 and DRISW to share this function, but it
202 * seems a better seperation and safer for each DRI version to provide its own
203 * function.
204 */
205void
206drisw_allocate_textures(struct dri_drawable *drawable,
207                        unsigned mask)
208{
209   struct dri_screen *screen = dri_screen(drawable->sPriv);
210   struct pipe_texture templ;
211   unsigned width, height;
212   boolean resized;
213   int i;
214
215   width  = drawable->dPriv->w;
216   height = drawable->dPriv->h;
217
218   resized = (drawable->old_w != width ||
219              drawable->old_h != height);
220
221   /* remove outdated textures */
222   if (resized) {
223      for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
224         pipe_texture_reference(&drawable->textures[i], NULL);
225   }
226
227   memset(&templ, 0, sizeof(templ));
228   templ.target = PIPE_TEXTURE_2D;
229   templ.width0 = width;
230   templ.height0 = height;
231   templ.depth0 = 1;
232   templ.last_level = 0;
233
234   for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
235      enum pipe_format format;
236      unsigned tex_usage;
237
238      /* the texture already exists or not requested */
239      if (drawable->textures[i] || !(mask & (1 << i))) {
240         continue;
241      }
242
243      switch (i) {
244      case ST_ATTACHMENT_FRONT_LEFT:
245      case ST_ATTACHMENT_BACK_LEFT:
246      case ST_ATTACHMENT_FRONT_RIGHT:
247      case ST_ATTACHMENT_BACK_RIGHT:
248         format = drawable->stvis.color_format;
249         tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
250                     PIPE_TEXTURE_USAGE_RENDER_TARGET;
251         break;
252      case ST_ATTACHMENT_DEPTH_STENCIL:
253         format = drawable->stvis.depth_stencil_format;
254         tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
255         break;
256      default:
257         format = PIPE_FORMAT_NONE;
258         break;
259      }
260
261      if (format != PIPE_FORMAT_NONE) {
262         templ.format = format;
263         templ.tex_usage = tex_usage;
264
265         drawable->textures[i] =
266            screen->pipe_screen->texture_create(screen->pipe_screen, &templ);
267      }
268   }
269
270   drawable->old_w = width;
271   drawable->old_h = height;
272}
273
274/*
275 * Backend function for init_screen.
276 */
277
278static const __DRIextension *drisw_screen_extensions[] = {
279   NULL
280};
281
282const __DRIconfig **
283drisw_init_screen(__DRIscreen * sPriv)
284{
285   struct dri_screen *screen;
286   struct drm_create_screen_arg arg;
287
288   screen = CALLOC_STRUCT(dri_screen);
289   if (!screen)
290      return NULL;
291
292   screen->api = drm_api_create();
293   screen->sPriv = sPriv;
294   screen->fd = -1;
295   sPriv->private = (void *)screen;
296   sPriv->extensions = drisw_screen_extensions;
297   arg.mode = DRM_CREATE_DRISW;
298
299   screen->pipe_screen = screen->api->create_screen(screen->api, -1, &arg);
300   if (!screen->pipe_screen) {
301      debug_printf("%s: failed to create pipe_screen\n", __FUNCTION__);
302      goto fail;
303   }
304
305   screen->smapi = dri_create_st_manager(screen);
306   if (!screen->smapi)
307      goto fail;
308
309   driParseOptionInfo(&screen->optionCache,
310                      __driConfigOptions, __driNConfigOptions);
311
312   return dri_fill_in_modes(screen, 32);
313fail:
314   dri_destroy_screen(sPriv);
315   return NULL;
316}
317
318/* This is the table of extensions that the loader will dlsym() for. */
319PUBLIC const __DRIextension *__driDriverExtensions[] = {
320    &driCoreExtension.base,
321    &driSWRastExtension.base,
322    NULL
323};
324
325/* vim: set sw=3 ts=8 sts=3 expandtab: */
326