gallium/st + hgl: Build fixes for Haiku
[mesa.git] / src / gallium / targets / haiku-softpipe / GalliumContext.cpp
1 /*
2 * Copyright 2012, 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
11 #include "GalliumContext.h"
12
13 #include <stdio.h>
14
15 #include "GLView.h"
16
17 #include "bitmap_wrapper.h"
18 extern "C" {
19 #include "glapi/glapi.h"
20 #include "pipe/p_format.h"
21 #include "state_tracker/st_cb_fbo.h"
22 #include "state_tracker/st_cb_flush.h"
23 #include "state_tracker/st_context.h"
24 #include "state_tracker/st_gl_api.h"
25 #include "state_tracker/st_manager.h"
26 #include "state_tracker/sw_winsys.h"
27 #include "sw/hgl/hgl_sw_winsys.h"
28 #include "util/u_atomic.h"
29 #include "util/u_memory.h"
30
31 #include "target-helpers/inline_sw_helper.h"
32 #include "target-helpers/inline_debug_helper.h"
33 }
34
35
36 #ifdef DEBUG
37 # define TRACE(x...) printf("GalliumContext: " x)
38 # define CALLED() TRACE("CALLED: %s\n", __PRETTY_FUNCTION__)
39 #else
40 # define TRACE(x...)
41 # define CALLED()
42 #endif
43 #define ERROR(x...) printf("GalliumContext: " x)
44
45
46 GalliumContext::GalliumContext(ulong options)
47 :
48 fOptions(options),
49 fScreen(NULL),
50 fCurrentContext(0)
51 {
52 CALLED();
53
54 // Make all contexts a known value
55 for (context_id i = 0; i < CONTEXT_MAX; i++)
56 fContext[i] = NULL;
57
58 CreateScreen();
59
60 pipe_mutex_init(fMutex);
61 }
62
63
64 GalliumContext::~GalliumContext()
65 {
66 CALLED();
67
68 // Destroy our contexts
69 Lock();
70 for (context_id i = 0; i < CONTEXT_MAX; i++)
71 DestroyContext(i);
72 Unlock();
73
74 pipe_mutex_destroy(fMutex);
75
76 // TODO: Destroy fScreen
77 }
78
79
80 status_t
81 GalliumContext::CreateScreen()
82 {
83 CALLED();
84
85 // Allocate winsys and attach callback hooks
86 struct sw_winsys* winsys = hgl_create_sw_winsys();
87
88 if (!winsys) {
89 ERROR("%s: Couldn't allocate sw_winsys!\n", __func__);
90 return B_ERROR;
91 }
92
93 fScreen = sw_screen_create(winsys);
94
95 if (fScreen == NULL) {
96 ERROR("%s: Couldn't create screen!\n", __FUNCTION__);
97 FREE(winsys);
98 return B_ERROR;
99 }
100
101 debug_screen_wrap(fScreen);
102
103 const char* driverName = fScreen->get_name(fScreen);
104 ERROR("%s: Using %s driver.\n", __func__, driverName);
105
106 return B_OK;
107 }
108
109
110 context_id
111 GalliumContext::CreateContext(Bitmap *bitmap)
112 {
113 CALLED();
114
115 struct hgl_context* context = CALLOC_STRUCT(hgl_context);
116
117 if (!context) {
118 ERROR("%s: Couldn't create pipe context!\n", __FUNCTION__);
119 return 0;
120 }
121
122 // Set up the initial things our context needs
123 context->bitmap = bitmap;
124 context->colorSpace = get_bitmap_color_space(bitmap);
125 context->screen = fScreen;
126 context->draw = NULL;
127 context->read = NULL;
128 context->st = NULL;
129
130 context->api = st_gl_api_create();
131 if (!context->api) {
132 ERROR("%s: Couldn't obtain Mesa state tracker API!\n", __func__);
133 return -1;
134 }
135
136 // Create state_tracker manager
137 context->manager = hgl_create_st_manager(context);
138
139 // Create state tracker visual
140 context->stVisual = hgl_create_st_visual(fOptions);
141
142 // Create state tracker framebuffers
143 context->draw = hgl_create_st_framebuffer(context);
144 context->read = hgl_create_st_framebuffer(context);
145
146 if (!context->draw || !context->read) {
147 ERROR("%s: Problem allocating framebuffer!\n", __func__);
148 FREE(context->stVisual);
149 return -1;
150 }
151
152 // Build state tracker attributes
153 struct st_context_attribs attribs;
154 memset(&attribs, 0, sizeof(attribs));
155 attribs.options.force_glsl_extensions_warn = false;
156 attribs.profile = ST_PROFILE_DEFAULT;
157 attribs.visual = *context->stVisual;
158 attribs.major = 1;
159 attribs.minor = 0;
160 //attribs.flags |= ST_CONTEXT_FLAG_DEBUG;
161
162 struct st_api* api = context->api;
163
164 // Create context using state tracker api call
165 enum st_context_error result;
166 context->st = api->create_context(api, context->manager, &attribs,
167 &result, context->st);
168
169 if (!context->st) {
170 ERROR("%s: Couldn't create mesa state tracker context!\n",
171 __func__);
172 switch (result) {
173 case ST_CONTEXT_SUCCESS:
174 ERROR("%s: State tracker error: SUCCESS?\n", __func__);
175 break;
176 case ST_CONTEXT_ERROR_NO_MEMORY:
177 ERROR("%s: State tracker error: NO_MEMORY\n", __func__);
178 break;
179 case ST_CONTEXT_ERROR_BAD_API:
180 ERROR("%s: State tracker error: BAD_API\n", __func__);
181 break;
182 case ST_CONTEXT_ERROR_BAD_VERSION:
183 ERROR("%s: State tracker error: BAD_VERSION\n", __func__);
184 break;
185 case ST_CONTEXT_ERROR_BAD_FLAG:
186 ERROR("%s: State tracker error: BAD_FLAG\n", __func__);
187 break;
188 case ST_CONTEXT_ERROR_UNKNOWN_ATTRIBUTE:
189 ERROR("%s: State tracker error: BAD_ATTRIBUTE\n", __func__);
190 break;
191 case ST_CONTEXT_ERROR_UNKNOWN_FLAG:
192 ERROR("%s: State tracker error: UNKNOWN_FLAG\n", __func__);
193 break;
194 }
195
196 hgl_destroy_st_visual(context->stVisual);
197 FREE(context);
198 return -1;
199 }
200
201 assert(!context->st->st_manager_private);
202 context->st->st_manager_private = (void*)context;
203
204 struct st_context *stContext = (struct st_context*)context->st;
205
206 // Init Gallium3D Post Processing
207 // TODO: no pp filters are enabled yet through postProcessEnable
208 context->postProcess = pp_init(stContext->pipe, context->postProcessEnable,
209 stContext->cso_context);
210
211 context_id contextNext = -1;
212 Lock();
213 for (context_id i = 0; i < CONTEXT_MAX; i++) {
214 if (fContext[i] == NULL) {
215 fContext[i] = context;
216 contextNext = i;
217 break;
218 }
219 }
220 Unlock();
221
222 if (contextNext < 0) {
223 ERROR("%s: The next context is invalid... something went wrong!\n",
224 __func__);
225 //st_destroy_context(context->st);
226 FREE(context->stVisual);
227 FREE(context);
228 return -1;
229 }
230
231 TRACE("%s: context #%" B_PRIu64 " is the next available context\n",
232 __func__, contextNext);
233
234 return contextNext;
235 }
236
237
238 void
239 GalliumContext::DestroyContext(context_id contextID)
240 {
241 // fMutex should be locked *before* calling DestoryContext
242
243 // See if context is used
244 if (!fContext[contextID])
245 return;
246
247 if (fContext[contextID]->st) {
248 fContext[contextID]->st->flush(fContext[contextID]->st, 0, NULL);
249 fContext[contextID]->st->destroy(fContext[contextID]->st);
250 }
251
252 if (fContext[contextID]->postProcess)
253 pp_free(fContext[contextID]->postProcess);
254
255 // Delete state tracker framebuffer objects
256 if (fContext[contextID]->read)
257 delete fContext[contextID]->read;
258 if (fContext[contextID]->draw)
259 delete fContext[contextID]->draw;
260
261 if (fContext[contextID]->stVisual)
262 hgl_destroy_st_visual(fContext[contextID]->stVisual);
263
264 if (fContext[contextID]->manager)
265 hgl_destroy_st_manager(fContext[contextID]->manager);
266
267 FREE(fContext[contextID]);
268 }
269
270
271 status_t
272 GalliumContext::SetCurrentContext(Bitmap *bitmap, context_id contextID)
273 {
274 CALLED();
275
276 if (contextID < 0 || contextID > CONTEXT_MAX) {
277 ERROR("%s: Invalid context ID range!\n", __func__);
278 return B_ERROR;
279 }
280
281 Lock();
282 context_id oldContextID = fCurrentContext;
283 struct hgl_context* context = fContext[contextID];
284 Unlock();
285
286 if (!context) {
287 ERROR("%s: Invalid context provided (#%" B_PRIu64 ")!\n",
288 __func__, contextID);
289 return B_ERROR;
290 }
291
292 struct st_api* api = context->api;
293
294 if (!bitmap) {
295 api->make_current(context->api, NULL, NULL, NULL);
296 return B_OK;
297 }
298
299 // Everything seems valid, lets set the new context.
300 fCurrentContext = contextID;
301
302 if (oldContextID > 0 && oldContextID != contextID) {
303 fContext[oldContextID]->st->flush(fContext[oldContextID]->st,
304 ST_FLUSH_FRONT, NULL);
305 }
306
307 // We need to lock and unlock framebuffers before accessing them
308 api->make_current(context->api, context->st, context->draw->stfbi,
309 context->read->stfbi);
310
311 //if (context->textures[ST_ATTACHMENT_BACK_LEFT]
312 // && context->textures[ST_ATTACHMENT_DEPTH_STENCIL]
313 // && context->postProcess) {
314 // TRACE("Postprocessing textures...\n");
315 // pp_init_fbos(context->postProcess,
316 // context->textures[ST_ATTACHMENT_BACK_LEFT]->width0,
317 // context->textures[ST_ATTACHMENT_BACK_LEFT]->height0);
318 //}
319
320 context->bitmap = bitmap;
321 //context->st->pipe->priv = context;
322
323 return B_OK;
324 }
325
326
327 status_t
328 GalliumContext::SwapBuffers(context_id contextID)
329 {
330 CALLED();
331
332 Lock();
333 struct hgl_context *context = fContext[contextID];
334 Unlock();
335
336 if (!context) {
337 ERROR("%s: context not found\n", __func__);
338 return B_ERROR;
339 }
340
341 // TODO: Where did st_notify_swapbuffers go?
342 //st_notify_swapbuffers(context->draw->stfbi);
343
344 context->st->flush(context->st, ST_FLUSH_FRONT, NULL);
345
346 struct st_context *stContext = (struct st_context*)context->st;
347
348 unsigned nColorBuffers = stContext->state.framebuffer.nr_cbufs;
349 for (unsigned i = 0; i < nColorBuffers; i++) {
350 pipe_surface* surface = stContext->state.framebuffer.cbufs[i];
351 if (!surface) {
352 ERROR("%s: Color buffer %d invalid!\n", __func__, i);
353 continue;
354 }
355
356 TRACE("%s: Flushing color buffer #%d\n", __func__, i);
357
358 // We pass our destination bitmap to flush_fronbuffer which passes it
359 // to the private winsys display call.
360 fScreen->flush_frontbuffer(fScreen, surface->texture, 0, 0,
361 context->bitmap, NULL);
362 }
363
364 #if 0
365 // TODO... should we flush the z stencil buffer?
366 pipe_surface* zSurface = stContext->state.framebuffer.zsbuf;
367 fScreen->flush_frontbuffer(fScreen, zSurface->texture, 0, 0,
368 context->bitmap, NULL);
369 #endif
370
371 return B_OK;
372 }
373
374
375 bool
376 GalliumContext::Validate(uint32 width, uint32 height)
377 {
378 CALLED();
379
380 if (!fContext[fCurrentContext]) {
381 return false;
382 }
383
384 if (fContext[fCurrentContext]->width != width
385 || fContext[fCurrentContext]->height != height) {
386 Invalidate(width, height);
387 return false;
388 }
389 return true;
390 }
391
392
393 void
394 GalliumContext::Invalidate(uint32 width, uint32 height)
395 {
396 CALLED();
397
398 assert(fContext[fCurrentContext]);
399
400 // Update st_context dimensions
401 fContext[fCurrentContext]->width = width;
402 fContext[fCurrentContext]->height = height;
403
404 // Is this the best way to invalidate?
405 p_atomic_inc(&fContext[fCurrentContext]->read->stfbi->stamp);
406 p_atomic_inc(&fContext[fCurrentContext]->draw->stfbi->stamp);
407 }
408
409
410 void
411 GalliumContext::Lock()
412 {
413 CALLED();
414 pipe_mutex_lock(fMutex);
415 }
416
417
418 void
419 GalliumContext::Unlock()
420 {
421 CALLED();
422 pipe_mutex_unlock(fMutex);
423 }
424 /* vim: set tabstop=4: */