xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/hgl/hgl.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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