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