xm_st.c revision 72ed7eb15a12ad88647dddefde5999ddd308b9e4
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.9
4 *
5 * Copyright (C) 2010 LunarG Inc.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 *    Chia-I Wu <olv@lunarg.com>
26 */
27
28#include "util/u_memory.h"
29#include "util/u_inlines.h"
30
31#include "xm_api.h"
32#include "xm_st.h"
33
34/* support OpenGL by default */
35#ifndef XMESA_ST_MODULE
36#define XMESA_ST_MODULE st_module_OpenGL
37#endif
38
39struct xmesa_st_framebuffer {
40   struct pipe_screen *screen;
41   XMesaBuffer buffer;
42
43   struct st_visual stvis;
44
45   unsigned texture_width, texture_height;
46   struct pipe_texture *textures[ST_ATTACHMENT_COUNT];
47
48   struct pipe_surface *display_surface;
49};
50
51static INLINE struct xmesa_st_framebuffer *
52xmesa_st_framebuffer(struct st_framebuffer_iface *stfbi)
53{
54   return (struct xmesa_st_framebuffer *) stfbi->st_manager_private;
55}
56
57/**
58 * Display an attachment to the xlib_drawable of the framebuffer.
59 */
60static boolean
61xmesa_st_framebuffer_display(struct st_framebuffer_iface *stfbi,
62                             enum st_attachment_type statt)
63{
64   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
65   struct pipe_texture *ptex = xstfb->textures[statt];
66   struct pipe_surface *psurf;
67
68   if (!ptex)
69      return TRUE;
70
71   psurf = xstfb->display_surface;
72   /* (re)allocate the surface for the texture to be displayed */
73   if (!psurf || psurf->texture != ptex) {
74      pipe_surface_reference(&xstfb->display_surface, NULL);
75
76      psurf = xstfb->screen->get_tex_surface(xstfb->screen,
77            ptex, 0, 0, 0, PIPE_BUFFER_USAGE_CPU_READ);
78      if (!psurf)
79         return FALSE;
80
81      xstfb->display_surface = psurf;
82   }
83
84   xstfb->screen->flush_frontbuffer(xstfb->screen, psurf, &xstfb->buffer->ws);
85
86   return TRUE;
87}
88
89/**
90 * Remove outdated textures and create the requested ones.
91 */
92static void
93xmesa_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi,
94                                       const enum st_attachment_type *statts,
95                                       unsigned count)
96{
97   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
98   struct pipe_texture templ;
99   unsigned request_mask, i;
100
101   request_mask = 0;
102   for (i = 0; i < count; i++)
103      request_mask |= 1 << statts[i];
104
105   memset(&templ, 0, sizeof(templ));
106   templ.target = PIPE_TEXTURE_2D;
107   templ.width0 = xstfb->texture_width;
108   templ.height0 = xstfb->texture_height;
109   templ.depth0 = 1;
110   templ.last_level = 0;
111
112   for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
113      struct pipe_texture *ptex = xstfb->textures[i];
114      enum pipe_format format;
115      unsigned tex_usage;
116
117      /* remove outdated textures */
118      if (ptex && (ptex->width0 != xstfb->texture_width ||
119                   ptex->height0 != xstfb->texture_height)) {
120         pipe_texture_reference(&xstfb->textures[i], NULL);
121         ptex = NULL;
122      }
123
124      /* the texture already exists or not requested */
125      if (ptex || !(request_mask & (1 << i)))
126         continue;
127
128      switch (i) {
129      case ST_ATTACHMENT_FRONT_LEFT:
130      case ST_ATTACHMENT_BACK_LEFT:
131      case ST_ATTACHMENT_FRONT_RIGHT:
132      case ST_ATTACHMENT_BACK_RIGHT:
133         format = xstfb->stvis.color_format;
134         tex_usage = PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
135                     PIPE_TEXTURE_USAGE_RENDER_TARGET;
136         break;
137      case ST_ATTACHMENT_DEPTH_STENCIL:
138         format = xstfb->stvis.depth_stencil_format;
139         tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
140         break;
141      default:
142         format = PIPE_FORMAT_NONE;
143         break;
144      }
145
146      if (format != PIPE_FORMAT_NONE) {
147         templ.format = format;
148         templ.tex_usage = tex_usage;
149
150         xstfb->textures[i] =
151            xstfb->screen->texture_create(xstfb->screen, &templ);
152      }
153   }
154}
155
156static boolean
157xmesa_st_framebuffer_validate(struct st_framebuffer_iface *stfbi,
158                              const enum st_attachment_type *statts,
159                              unsigned count,
160                              struct pipe_texture **out)
161{
162   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
163   unsigned i;
164
165   /* revalidate textures */
166   if (xstfb->buffer->width != xstfb->texture_width ||
167       xstfb->buffer->height != xstfb->texture_height) {
168      xstfb->texture_width = xstfb->buffer->width;
169      xstfb->texture_height = xstfb->buffer->height;
170
171      xmesa_st_framebuffer_validate_textures(stfbi, statts, count);
172   }
173
174   for (i = 0; i < count; i++) {
175      out[i] = NULL;
176      pipe_texture_reference(&out[i], xstfb->textures[statts[i]]);
177   }
178
179   return TRUE;
180}
181
182static boolean
183xmesa_st_framebuffer_flush_front(struct st_framebuffer_iface *stfbi,
184                                 enum st_attachment_type statt)
185{
186   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
187   boolean ret;
188
189   ret = xmesa_st_framebuffer_display(stfbi, statt);
190   if (ret)
191      xmesa_check_buffer_size(xstfb->buffer);
192
193   return ret;
194}
195
196struct st_framebuffer_iface *
197xmesa_create_st_framebuffer(struct pipe_screen *screen, XMesaBuffer b)
198{
199   struct st_framebuffer_iface *stfbi;
200   struct xmesa_st_framebuffer *xstfb;
201
202   stfbi = CALLOC_STRUCT(st_framebuffer_iface);
203   xstfb = CALLOC_STRUCT(xmesa_st_framebuffer);
204   if (!stfbi || !xstfb) {
205      if (stfbi)
206         FREE(stfbi);
207      if (xstfb)
208         FREE(xstfb);
209      return NULL;
210   }
211
212   xstfb->screen = screen;
213   xstfb->buffer = b;
214   xstfb->stvis = b->xm_visual->stvis;
215
216   stfbi->visual = &xstfb->stvis;
217   stfbi->flush_front = xmesa_st_framebuffer_flush_front;
218   stfbi->validate = xmesa_st_framebuffer_validate;
219   stfbi->st_manager_private = (void *) xstfb;
220
221   return stfbi;
222}
223
224void
225xmesa_destroy_st_framebuffer(struct st_framebuffer_iface *stfbi)
226{
227   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
228
229   FREE(xstfb);
230   FREE(stfbi);
231}
232
233void
234xmesa_swap_st_framebuffer(struct st_framebuffer_iface *stfbi)
235{
236   struct xmesa_st_framebuffer *xstfb = xmesa_st_framebuffer(stfbi);
237   boolean ret;
238
239   ret = xmesa_st_framebuffer_display(stfbi, ST_ATTACHMENT_BACK_LEFT);
240   if (ret) {
241      struct pipe_texture **front, **back, *tmp;
242
243      front = &xstfb->textures[ST_ATTACHMENT_FRONT_LEFT];
244      back = &xstfb->textures[ST_ATTACHMENT_BACK_LEFT];
245      /* swap textures only if the front texture has been allocated */
246      if (*front) {
247         tmp = *front;
248         *front = *back;
249         *back = tmp;
250      }
251
252      xmesa_check_buffer_size(xstfb->buffer);
253   }
254}
255
256void
257xmesa_copy_st_framebuffer(struct st_framebuffer_iface *stfbi,
258                          enum st_attachment_type src,
259                          enum st_attachment_type dst,
260                          int x, int y, int w, int h)
261{
262   /* TODO */
263}
264
265struct st_api *
266xmesa_create_st_api(void)
267{
268   return XMESA_ST_MODULE.create_api();
269}
270