1 /*
2 * Copyright 2012-2014, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Artur Wyszynski, [email protected]
7 * Alexander von Gluck IV, [email protected]
8 */
9
10 #include "hgl_context.h"
11
12 #include <stdio.h>
13
14 #include "util/format/u_formats.h"
15 #include "util/u_atomic.h"
16 #include "util/format/u_format.h"
17 #include "util/u_memory.h"
18 #include "util/u_inlines.h"
19 #include "state_tracker/st_context.h"
20
21
22 #if MESA_DEBUG
23 # define TRACE(x...) printf("hgl:frontend: " x)
24 # define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
25 #else
26 # define TRACE(x...)
27 # define CALLED()
28 #endif
29 #define ERROR(x...) printf("hgl:frontend: " x)
30
31
32 // Perform a safe void to hgl_context cast
33 static inline struct hgl_context*
hgl_st_context(struct st_context * st)34 hgl_st_context(struct st_context *st)
35 {
36 struct hgl_context* context;
37 assert(st);
38 context = (struct hgl_context*)st->frontend_context;
39 assert(context);
40 return context;
41 }
42
43
44 // Perform a safe void to hgl_buffer cast
45 static struct hgl_buffer*
hgl_st_framebuffer(struct pipe_frontend_drawable * drawable)46 hgl_st_framebuffer(struct pipe_frontend_drawable *drawable)
47 {
48 struct hgl_buffer* buffer;
49 assert(drawable);
50 buffer = (struct hgl_buffer*)drawable;
51 assert(buffer);
52 return buffer;
53 }
54
55
56 static bool
hgl_st_framebuffer_flush_front(struct st_context * st,struct pipe_frontend_drawable * drawable,enum st_attachment_type statt)57 hgl_st_framebuffer_flush_front(struct st_context *st,
58 struct pipe_frontend_drawable* drawable, enum st_attachment_type statt)
59 {
60 CALLED();
61
62 struct hgl_buffer* buffer = hgl_st_framebuffer(drawable);
63 struct pipe_resource* ptex = buffer->textures[statt];
64
65 if (statt != ST_ATTACHMENT_FRONT_LEFT)
66 return false;
67
68 if (!ptex)
69 return true;
70
71 // TODO: pipe_context here??? Might be needed for hw renderers
72 buffer->screen->flush_frontbuffer(buffer->screen, NULL, ptex, 0, 0,
73 buffer->winsysContext, 0, NULL);
74
75 return true;
76 }
77
78
79 static bool
hgl_st_framebuffer_validate_textures(struct pipe_frontend_drawable * drawable,unsigned width,unsigned height,unsigned mask)80 hgl_st_framebuffer_validate_textures(struct pipe_frontend_drawable *drawable,
81 unsigned width, unsigned height, unsigned mask)
82 {
83 struct hgl_buffer* buffer;
84 enum st_attachment_type i;
85 struct pipe_resource templat;
86
87 CALLED();
88
89 buffer = hgl_st_framebuffer(drawable);
90
91 if (buffer->width != width || buffer->height != height) {
92 TRACE("validate_textures: size changed: %d, %d -> %d, %d\n",
93 buffer->width, buffer->height, width, height);
94 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
95 pipe_resource_reference(&buffer->textures[i], NULL);
96 }
97
98 memset(&templat, 0, sizeof(templat));
99 templat.target = buffer->target;
100 templat.width0 = width;
101 templat.height0 = height;
102 templat.depth0 = 1;
103 templat.array_size = 1;
104 templat.last_level = 0;
105
106 for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
107 enum pipe_format format;
108 unsigned bind;
109
110 if (((1 << i) & buffer->visual.buffer_mask) && buffer->textures[i] == NULL) {
111 switch (i) {
112 case ST_ATTACHMENT_FRONT_LEFT:
113 case ST_ATTACHMENT_BACK_LEFT:
114 case ST_ATTACHMENT_FRONT_RIGHT:
115 case ST_ATTACHMENT_BACK_RIGHT:
116 format = buffer->visual.color_format;
117 bind = PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_RENDER_TARGET;
118 break;
119 case ST_ATTACHMENT_DEPTH_STENCIL:
120 format = buffer->visual.depth_stencil_format;
121 bind = PIPE_BIND_DEPTH_STENCIL;
122 break;
123 default:
124 format = PIPE_FORMAT_NONE;
125 bind = 0;
126 break;
127 }
128
129 if (format != PIPE_FORMAT_NONE) {
130 templat.format = format;
131 templat.bind = bind;
132 TRACE("resource_create(%d, %d, %d)\n", i, format, bind);
133 buffer->textures[i] = buffer->screen->resource_create(buffer->screen,
134 &templat);
135 if (!buffer->textures[i])
136 return false;
137 }
138 }
139 }
140
141 buffer->width = width;
142 buffer->height = height;
143 buffer->mask = mask;
144
145 return true;
146 }
147
148
149 /**
150 * Called by the st manager to validate the framebuffer (allocate
151 * its resources).
152 */
153 static bool
hgl_st_framebuffer_validate(struct st_context * st,struct pipe_frontend_drawable * drawable,const enum st_attachment_type * statts,unsigned count,struct pipe_resource ** out,struct pipe_resource ** resolve)154 hgl_st_framebuffer_validate(struct st_context *st,
155 struct pipe_frontend_drawable *drawable, const enum st_attachment_type *statts,
156 unsigned count, struct pipe_resource **out, struct pipe_resource **resolve)
157 {
158 struct hgl_buffer* buffer;
159 unsigned stAttachmentMask, newMask;
160 unsigned i;
161 bool resized;
162
163 CALLED();
164
165 buffer = hgl_st_framebuffer(drawable);
166
167 // Build mask of current attachments
168 stAttachmentMask = 0;
169 for (i = 0; i < count; i++)
170 stAttachmentMask |= 1 << statts[i];
171
172 newMask = stAttachmentMask & ~buffer->mask;
173
174 resized = (buffer->width != buffer->newWidth)
175 || (buffer->height != buffer->newHeight);
176
177 if (resized || newMask) {
178 bool ret;
179 TRACE("%s: resize event. old: %d x %d; new: %d x %d\n", __func__,
180 buffer->width, buffer->height, buffer->newWidth, buffer->newHeight);
181
182 ret = hgl_st_framebuffer_validate_textures(drawable,
183 buffer->newWidth, buffer->newHeight, stAttachmentMask);
184
185 if (!ret)
186 return ret;
187 }
188
189 for (i = 0; i < count; i++)
190 pipe_resource_reference(&out[i], buffer->textures[statts[i]]);
191
192 return true;
193 }
194
195
196 static int
hgl_st_manager_get_param(struct pipe_frontend_screen * fscreen,enum st_manager_param param)197 hgl_st_manager_get_param(struct pipe_frontend_screen *fscreen, enum st_manager_param param)
198 {
199 CALLED();
200
201 switch (param) {
202 case ST_MANAGER_BROKEN_INVALIDATE:
203 return 1;
204 }
205
206 return 0;
207 }
208
209
210 static uint32_t hgl_fb_ID = 0;
211
212 /**
213 * Create new framebuffer
214 */
215 struct hgl_buffer *
hgl_create_st_framebuffer(struct hgl_display * display,struct st_visual * visual,void * winsysContext)216 hgl_create_st_framebuffer(struct hgl_display *display, struct st_visual* visual, void *winsysContext)
217 {
218 struct hgl_buffer *buffer;
219 CALLED();
220
221 // Our requires before creating a framebuffer
222 assert(display);
223 assert(visual);
224
225 buffer = CALLOC_STRUCT(hgl_buffer);
226 assert(buffer);
227
228 // Prepare our buffer
229 buffer->visual = *visual;
230 buffer->screen = display->fscreen->screen;
231 buffer->winsysContext = winsysContext;
232
233 if (buffer->screen->get_param(buffer->screen, PIPE_CAP_NPOT_TEXTURES))
234 buffer->target = PIPE_TEXTURE_2D;
235 else
236 buffer->target = PIPE_TEXTURE_RECT;
237
238 // Prepare our frontend interface
239 buffer->base.flush_front = hgl_st_framebuffer_flush_front;
240 buffer->base.validate = hgl_st_framebuffer_validate;
241 buffer->base.visual = &buffer->visual;
242
243 p_atomic_set(&buffer->base.stamp, 1);
244 buffer->base.ID = p_atomic_inc_return(&hgl_fb_ID);
245 buffer->base.fscreen = display->fscreen;
246
247 return buffer;
248 }
249
250
251 void
hgl_destroy_st_framebuffer(struct hgl_buffer * buffer)252 hgl_destroy_st_framebuffer(struct hgl_buffer *buffer)
253 {
254 CALLED();
255
256 int i;
257 for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
258 pipe_resource_reference(&buffer->textures[i], NULL);
259
260 FREE(buffer);
261 }
262
263
264 struct hgl_context*
hgl_create_context(struct hgl_display * display,struct st_visual * visual,struct st_context * shared)265 hgl_create_context(struct hgl_display *display, struct st_visual* visual, struct st_context* shared)
266 {
267 struct hgl_context* context = CALLOC_STRUCT(hgl_context);
268 assert(context);
269 context->display = display;
270
271 struct st_context_attribs attribs;
272 memset(&attribs, 0, sizeof(attribs));
273 attribs.options.force_glsl_extensions_warn = false;
274 attribs.profile = API_OPENGL_COMPAT;
275 attribs.visual = *visual;
276 attribs.major = 1;
277 attribs.minor = 0;
278
279 enum st_context_error result;
280 context->st = st_api_create_context(display->fscreen, &attribs, &result, shared);
281 if (context->st == NULL) {
282 FREE(context);
283 return NULL;
284 }
285
286 assert(!context->st->frontend_context);
287 context->st->frontend_context = (void*)context;
288
289 struct st_context *stContext = (struct st_context*)context->st;
290
291 // Init Gallium3D Post Processing
292 // TODO: no pp filters are enabled yet through postProcessEnable
293 context->postProcess = pp_init(stContext->pipe, context->postProcessEnable, stContext->cso_context, stContext, (void*)st_context_invalidate_state);
294
295 return context;
296 }
297
298
299 void
hgl_destroy_context(struct hgl_context * context)300 hgl_destroy_context(struct hgl_context* context)
301 {
302 if (context->st) {
303 st_context_flush(context->st, 0, NULL, NULL, NULL);
304 st_destroy_context(context->st);
305 }
306
307 if (context->postProcess)
308 pp_free(context->postProcess);
309
310 FREE(context);
311 }
312
313
314 void
hgl_get_st_visual(struct st_visual * visual,ulong options)315 hgl_get_st_visual(struct st_visual* visual, ulong options)
316 {
317 CALLED();
318
319 assert(visual);
320
321 // Determine color format
322 if ((options & HGL_INDEX) != 0) {
323 // Index color
324 visual->color_format = PIPE_FORMAT_B5G6R5_UNORM;
325 // TODO: Indexed color depth buffer?
326 visual->depth_stencil_format = PIPE_FORMAT_NONE;
327 } else {
328 // RGB color
329 visual->color_format = (options & HGL_ALPHA)
330 ? PIPE_FORMAT_BGRA8888_UNORM : PIPE_FORMAT_BGRX8888_UNORM;
331 // TODO: Determine additional stencil formats
332 visual->depth_stencil_format = (options & HGL_DEPTH)
333 ? PIPE_FORMAT_Z24_UNORM_S8_UINT : PIPE_FORMAT_NONE;
334 }
335
336 visual->accum_format = (options & HGL_ACCUM)
337 ? PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
338
339 visual->buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK;
340
341 if ((options & HGL_DOUBLE) != 0) {
342 TRACE("double buffer enabled\n");
343 visual->buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
344 }
345
346 #if 0
347 if ((options & HGL_STEREO) != 0) {
348 visual->buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
349 if ((options & HGL_DOUBLE) != 0)
350 visual->buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
351 }
352 #endif
353
354 if ((options & HGL_DEPTH) || (options & HGL_STENCIL))
355 visual->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
356
357 TRACE("%s: Visual color format: %s\n", __func__,
358 util_format_name(visual->color_format));
359 }
360
361
362 struct hgl_display*
hgl_create_display(struct pipe_screen * screen)363 hgl_create_display(struct pipe_screen* screen)
364 {
365 struct hgl_display* display;
366
367 display = CALLOC_STRUCT(hgl_display);
368 assert(display);
369 display->fscreen = CALLOC_STRUCT(pipe_frontend_screen);
370 assert(display->fscreen);
371 display->fscreen->screen = screen;
372 display->fscreen->get_param = hgl_st_manager_get_param;
373 // display->fscreen->st_screen is used by llvmpipe
374
375 return display;
376 }
377
378
379 void
hgl_destroy_display(struct hgl_display * display)380 hgl_destroy_display(struct hgl_display *display)
381 {
382 st_screen_destroy(display->fscreen);
383 FREE(display->fscreen);
384 FREE(display);
385 }
386