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