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/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:state_tracker: " 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:state_tracker: " 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
47static inline struct hgl_buffer*
48hgl_st_framebuffer(struct st_framebuffer_iface *stfbi)
49{
50	struct hgl_buffer* buffer;
51	assert(stfbi);
52	buffer = (struct hgl_buffer*)stfbi->st_manager_private;
53	assert(buffer);
54	return buffer;
55}
56
57
58static boolean
59hgl_st_framebuffer_flush_front(struct st_context_iface *stctxi,
60	struct st_framebuffer_iface* stfbi, enum st_attachment_type statt)
61{
62	CALLED();
63
64	//struct hgl_context* context = hgl_st_context(stctxi);
65	//struct hgl_buffer* buffer = hgl_st_context(stfbi);
66
67	#if 0
68	struct stw_st_framebuffer *stwfb = stw_st_framebuffer(stfb);
69	mtx_lock(&stwfb->fb->mutex);
70
71	struct pipe_resource* resource = textures[statt];
72	if (resource)
73		stw_framebuffer_present_locked(...);
74	#endif
75
76	return TRUE;
77}
78
79
80static boolean
81hgl_st_framebuffer_validate_textures(struct st_framebuffer_iface *stfbi,
82	unsigned width, unsigned height, unsigned mask)
83{
84	struct hgl_buffer* buffer;
85	enum st_attachment_type i;
86	struct pipe_resource templat;
87
88	CALLED();
89
90	buffer = hgl_st_framebuffer(stfbi);
91
92	if (buffer->width != width || buffer->height != height) {
93		for (i = 0; i < ST_ATTACHMENT_COUNT; i++)
94			pipe_resource_reference(&buffer->textures[i], NULL);
95	}
96
97	memset(&templat, 0, sizeof(templat));
98	templat.target = buffer->target;
99	templat.width0 = width;
100	templat.height0 = height;
101	templat.depth0 = 1;
102	templat.array_size = 1;
103	templat.last_level = 0;
104
105	for (i = 0; i < ST_ATTACHMENT_COUNT; i++) {
106		enum pipe_format format;
107		unsigned bind;
108
109		switch (i) {
110			case ST_ATTACHMENT_FRONT_LEFT:
111			case ST_ATTACHMENT_BACK_LEFT:
112			case ST_ATTACHMENT_FRONT_RIGHT:
113			case ST_ATTACHMENT_BACK_RIGHT:
114				format = buffer->visual->color_format;
115				bind = PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_RENDER_TARGET;
116				break;
117			case ST_ATTACHMENT_DEPTH_STENCIL:
118				format = buffer->visual->depth_stencil_format;
119				bind = PIPE_BIND_DEPTH_STENCIL;
120				break;
121			default:
122				format = PIPE_FORMAT_NONE;
123				bind = 0;
124				break;
125		}
126
127		if (format != PIPE_FORMAT_NONE) {
128			templat.format = format;
129			templat.bind = bind;
130			buffer->textures[i] = buffer->screen->resource_create(buffer->screen,
131				&templat);
132			if (!buffer->textures[i])
133				return FALSE;
134		}
135	}
136
137	buffer->width = width;
138	buffer->height = height;
139	buffer->mask = mask;
140
141	return TRUE;
142}
143
144
145/**
146 * Called by the st manager to validate the framebuffer (allocate
147 * its resources).
148 */
149static boolean
150hgl_st_framebuffer_validate(struct st_context_iface *stctxi,
151	struct st_framebuffer_iface *stfbi, const enum st_attachment_type *statts,
152	unsigned count, struct pipe_resource **out)
153{
154	struct hgl_context* context;
155	struct hgl_buffer* buffer;
156	unsigned stAttachmentMask, newMask;
157	unsigned i;
158	boolean resized;
159
160	CALLED();
161
162	context = hgl_st_context(stctxi);
163	buffer = hgl_st_framebuffer(stfbi);
164
165	//int32 width = 0;
166	//int32 height = 0;
167	//get_bitmap_size(context->bitmap, &width, &height);
168
169	// Build mask of current attachments
170	stAttachmentMask = 0;
171	for (i = 0; i < count; i++)
172		stAttachmentMask |= 1 << statts[i];
173
174	newMask = stAttachmentMask & ~buffer->mask;
175
176	resized = (buffer->width != context->width)
177		|| (buffer->height != context->height);
178
179	if (resized || newMask) {
180		boolean ret;
181		TRACE("%s: resize event. old:  %d x %d; new: %d x %d\n", __func__,
182			buffer->width, buffer->height, context->width, context->height);
183
184		ret = hgl_st_framebuffer_validate_textures(stfbi,
185			context->width, context->height, stAttachmentMask);
186
187		if (!ret)
188			return ret;
189
190		// TODO: Simply update attachments
191		//if (!resized) {
192
193		//}
194	}
195
196	for (i = 0; i < count; i++)
197		pipe_resource_reference(&out[i], buffer->textures[statts[i]]);
198
199	return TRUE;
200}
201
202
203static int
204hgl_st_manager_get_param(struct st_manager *smapi, enum st_manager_param param)
205{
206	CALLED();
207
208	switch (param) {
209		case ST_MANAGER_BROKEN_INVALIDATE:
210			return 1;
211	}
212
213	return 0;
214}
215
216
217/**
218 * Create new framebuffer
219 */
220struct hgl_buffer *
221hgl_create_st_framebuffer(struct hgl_context* context)
222{
223	struct hgl_buffer *buffer;
224	CALLED();
225
226	// Our requires before creating a framebuffer
227	assert(context);
228	assert(context->screen);
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->screen;
241
242	if (context->screen->get_param(buffer->screen, PIPE_CAP_NPOT_TEXTURES))
243		buffer->target = PIPE_TEXTURE_2D;
244	else
245		buffer->target = PIPE_TEXTURE_RECT;
246
247	// Prepare our state_tracker interface
248	buffer->stfbi->flush_front = hgl_st_framebuffer_flush_front;
249	buffer->stfbi->validate = hgl_st_framebuffer_validate;
250	buffer->stfbi->visual = context->stVisual;
251
252	p_atomic_set(&buffer->stfbi->stamp, 1);
253	buffer->stfbi->st_manager_private = (void*)buffer;
254
255	return buffer;
256}
257
258
259struct st_api*
260hgl_create_st_api()
261{
262	CALLED();
263	return st_gl_api_create();
264}
265
266
267struct st_manager *
268hgl_create_st_manager(struct hgl_context* context)
269{
270	struct st_manager* manager;
271
272	CALLED();
273
274	// Required things
275	assert(context);
276	assert(context->screen);
277
278	manager = CALLOC_STRUCT(st_manager);
279	assert(manager);
280
281	//manager->display = dpy;
282	manager->screen = context->screen;
283	manager->get_param = hgl_st_manager_get_param;
284
285	return manager;
286}
287
288
289void
290hgl_destroy_st_manager(struct st_manager *manager)
291{
292	CALLED();
293
294	FREE(manager);
295}
296
297
298struct st_visual*
299hgl_create_st_visual(ulong options)
300{
301	struct st_visual* visual;
302
303	CALLED();
304
305	visual = CALLOC_STRUCT(st_visual);
306	assert(visual);
307
308	// Determine color format
309	if ((options & BGL_INDEX) != 0) {
310		// Index color
311		visual->color_format = PIPE_FORMAT_B5G6R5_UNORM;
312		// TODO: Indexed color depth buffer?
313		visual->depth_stencil_format = PIPE_FORMAT_NONE;
314	} else {
315		// RGB color
316		visual->color_format = (options & BGL_ALPHA)
317			? PIPE_FORMAT_BGRA8888_UNORM : PIPE_FORMAT_BGRX8888_UNORM;
318		// TODO: Determine additional stencil formats
319		visual->depth_stencil_format = (options & BGL_DEPTH)
320			? PIPE_FORMAT_Z24_UNORM_S8_UINT : PIPE_FORMAT_NONE;
321    }
322
323	visual->accum_format = (options & BGL_ACCUM)
324		? PIPE_FORMAT_R16G16B16A16_SNORM : PIPE_FORMAT_NONE;
325
326	visual->buffer_mask |= ST_ATTACHMENT_FRONT_LEFT_MASK;
327	visual->render_buffer = ST_ATTACHMENT_FRONT_LEFT;
328
329	if ((options & BGL_DOUBLE) != 0) {
330		visual->buffer_mask |= ST_ATTACHMENT_BACK_LEFT_MASK;
331		visual->render_buffer = ST_ATTACHMENT_BACK_LEFT;
332	}
333
334	#if 0
335	if ((options & BGL_STEREO) != 0) {
336		visual->buffer_mask |= ST_ATTACHMENT_FRONT_RIGHT_MASK;
337		if ((options & BGL_DOUBLE) != 0)
338			visual->buffer_mask |= ST_ATTACHMENT_BACK_RIGHT_MASK;
339    }
340	#endif
341
342	if ((options & BGL_DEPTH) || (options & BGL_STENCIL))
343		visual->buffer_mask |= ST_ATTACHMENT_DEPTH_STENCIL_MASK;
344
345	TRACE("%s: Visual color format: %s\n", __func__,
346		util_format_name(visual->color_format));
347
348	return visual;
349}
350
351
352void
353hgl_destroy_st_visual(struct st_visual* visual)
354{
355	CALLED();
356
357	FREE(visual);
358}
359