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