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
35static inline struct hgl_context*
36hgl_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*
48struct hgl_buffer*
49hgl_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
59static bool
60hgl_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
82static bool
83hgl_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 */
156static bool
157hgl_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
201static int
202hgl_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
215static uint32_t hgl_fb_ID = 0;
216
217/**
218 * Create new framebuffer
219 */
220struct hgl_buffer *
221hgl_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
262void
263hgl_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
276struct st_api*
277hgl_create_st_api()
278{
279	CALLED();
280	return st_gl_api_create();
281}
282
283
284struct st_visual*
285hgl_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
337void
338hgl_destroy_st_visual(struct st_visual* visual)
339{
340	CALLED();
341
342	FREE(visual);
343}
344
345
346struct hgl_display*
347hgl_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
364void
365hgl_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