mesa: Change many Type A MESA_FORMATs to meet naming standard
[mesa.git] / src / mesa / drivers / haiku / swrast / SoftwareRast.cpp
1 /*
2 * Copyright 2006-2012, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Jérôme Duval, korli@users.berlios.de
7 * Philippe Houdoin, philippe.houdoin@free.fr
8 * Artur Wyszynski, harakash@gmail.com
9 * Alexander von Gluck, kallisti5@unixzen.com
10 */
11
12
13 #include <kernel/image.h>
14 #include "SoftwareRast.h"
15
16 #include <Autolock.h>
17 #include <interface/DirectWindowPrivate.h>
18 #include <GraphicsDefs.h>
19 #include <Screen.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 extern "C" {
24 #include "extensions.h"
25 #include "drivers/common/driverfuncs.h"
26 #include "drivers/common/meta.h"
27 #include "main/api_exec.h"
28 #include "main/colormac.h"
29 #include "main/cpuinfo.h"
30 #include "main/buffers.h"
31 #include "main/formats.h"
32 #include "main/framebuffer.h"
33 #include "main/renderbuffer.h"
34 #include "main/version.h"
35 #include "main/vtxfmt.h"
36 #include "swrast/swrast.h"
37 #include "swrast/s_renderbuffer.h"
38 #include "swrast_setup/swrast_setup.h"
39 #include "tnl/tnl.h"
40 #include "tnl/t_context.h"
41 #include "tnl/t_pipeline.h"
42 #include "vbo/vbo.h"
43
44
45 #ifdef DEBUG
46 # define TRACE(x...) printf("MesaSoftwareRast: " x)
47 # define CALLED() printf("MesaSoftwareRast: %s\n", __PRETTY_FUNCTION__)
48 #else
49 # define TRACE(x...)
50 # define CALLED()
51 #endif
52
53 #define ERROR(x...) printf("MesaSoftwareRast: " x)
54 }
55
56
57 extern const char* color_space_name(color_space space);
58
59
60 extern "C" _EXPORT BGLRenderer*
61 instantiate_gl_renderer(BGLView* view, ulong options,
62 BGLDispatcher* dispatcher)
63 {
64 return new MesaSoftwareRast(view, options, dispatcher);
65 }
66
67
68 MesaSoftwareRast::MesaSoftwareRast(BGLView* view, ulong options,
69 BGLDispatcher* dispatcher)
70 : BGLRenderer(view, options, dispatcher),
71 fBitmap(NULL),
72 fDirectModeEnabled(false),
73 fInfo(NULL),
74 fInfoLocker("info locker"),
75 fVisual(NULL),
76 fFrameBuffer(NULL),
77 fFrontRenderBuffer(NULL),
78 fBackRenderBuffer(NULL),
79 fColorSpace(B_NO_COLOR_SPACE)
80 {
81 CALLED();
82
83 fColorSpace = BScreen(GLView()->Window()).ColorSpace();
84
85 // We force single buffering for the time being
86 options &= ~BGL_DOUBLE;
87
88 const GLboolean rgbFlag = ((options & BGL_INDEX) == 0);
89 const GLboolean alphaFlag = ((options & BGL_ALPHA) == BGL_ALPHA);
90 const GLboolean dblFlag = ((options & BGL_DOUBLE) == BGL_DOUBLE);
91 const GLboolean stereoFlag = false;
92 const GLint depth = (options & BGL_DEPTH) ? 16 : 0;
93 const GLint stencil = (options & BGL_STENCIL) ? 8 : 0;
94 const GLint accum = (options & BGL_ACCUM) ? 16 : 0;
95 const GLint red = rgbFlag ? 8 : 0;
96 const GLint green = rgbFlag ? 8 : 0;
97 const GLint blue = rgbFlag ? 8 : 0;
98 const GLint alpha = alphaFlag ? 8 : 0;
99
100 fOptions = options; // | BGL_INDIRECT;
101 struct dd_function_table functions;
102
103 fVisual = _mesa_create_visual(dblFlag, stereoFlag, red, green,
104 blue, alpha, depth, stencil, accum, accum, accum,
105 alpha ? accum : 0, 1);
106
107 // Initialize device driver function table
108 _mesa_init_driver_functions(&functions);
109
110 functions.GetString = _GetString;
111 functions.UpdateState = _UpdateState;
112 functions.MapRenderbuffer = _RenderBufferMap;
113 functions.Flush = _Flush;
114
115 // create core context
116 // We inherit gl_context to this class
117 _mesa_initialize_context(this, API_OPENGL_COMPAT, fVisual, NULL,
118 &functions);
119
120 /* Initialize the software rasterizer and helper modules. */
121 _swrast_CreateContext(this);
122 _vbo_CreateContext(this);
123 _tnl_CreateContext(this);
124 _swsetup_CreateContext(this);
125 _swsetup_Wakeup(this);
126
127 // Use default TCL pipeline
128 TNL_CONTEXT(this)->Driver.RunPipeline = _tnl_run_pipeline;
129
130 _mesa_meta_init(this);
131 _mesa_enable_sw_extensions(this);
132
133 _mesa_compute_version(this);
134
135 _mesa_initialize_dispatch_tables(this);
136 _mesa_initialize_vbo_vtxfmt(this);
137
138 // create core framebuffer
139 fFrameBuffer = _mesa_create_framebuffer(fVisual);
140 if (fFrameBuffer == NULL) {
141 ERROR("%s: Unable to calloc GL FrameBuffer!\n", __func__);
142 _mesa_destroy_visual(fVisual);
143 return;
144 }
145
146 // Setup front render buffer
147 fFrontRenderBuffer = _NewRenderBuffer(true);
148 if (fFrontRenderBuffer == NULL) {
149 ERROR("%s: FrontRenderBuffer is requested but unallocated!\n",
150 __func__);
151 _mesa_destroy_visual(fVisual);
152 free(fFrameBuffer);
153 return;
154 }
155 _mesa_add_renderbuffer(fFrameBuffer, BUFFER_FRONT_LEFT,
156 &fFrontRenderBuffer->Base);
157
158 // Setup back render buffer (if requested)
159 if (fVisual->doubleBufferMode) {
160 fBackRenderBuffer = _NewRenderBuffer(false);
161 if (fBackRenderBuffer == NULL) {
162 ERROR("%s: BackRenderBuffer is requested but unallocated!\n",
163 __func__);
164 _mesa_destroy_visual(fVisual);
165 free(fFrameBuffer);
166 return;
167 }
168 _mesa_add_renderbuffer(fFrameBuffer, BUFFER_BACK_LEFT,
169 &fBackRenderBuffer->Base);
170 }
171
172 _swrast_add_soft_renderbuffers(fFrameBuffer, GL_FALSE,
173 fVisual->haveDepthBuffer, fVisual->haveStencilBuffer,
174 fVisual->haveAccumBuffer, alphaFlag, GL_FALSE);
175
176 BRect bounds = view->Bounds();
177 fWidth = (GLint)bounds.Width();
178 fHeight = (GLint)bounds.Height();
179
180 // some stupid applications (Quake2) don't even think about calling LockGL()
181 // before using glGetString and its glGet*() friends...
182 // so make sure there is at least a valid context.
183
184 if (!_mesa_get_current_context()) {
185 LockGL();
186 // not needed, we don't have a looper yet: UnlockLooper();
187 }
188 }
189
190
191 MesaSoftwareRast::~MesaSoftwareRast()
192 {
193 CALLED();
194 _swsetup_DestroyContext(this);
195 _swrast_DestroyContext(this);
196 _tnl_DestroyContext(this);
197 _vbo_DestroyContext(this);
198 _mesa_destroy_visual(fVisual);
199 _mesa_destroy_framebuffer(fFrameBuffer);
200 _mesa_destroy_context(this);
201
202 free(fInfo);
203 free(fFrameBuffer);
204
205 delete fBitmap;
206 }
207
208
209 void
210 MesaSoftwareRast::LockGL()
211 {
212 CALLED();
213 BGLRenderer::LockGL();
214
215 _mesa_make_current(this, fFrameBuffer, fFrameBuffer);
216
217 color_space colorSpace = BScreen(GLView()->Window()).ColorSpace();
218
219 GLuint width = fWidth;
220 GLuint height = fHeight;
221
222 BAutolock lock(fInfoLocker);
223 if (fDirectModeEnabled && fInfo != NULL) {
224 width = fInfo->window_bounds.right
225 - fInfo->window_bounds.left + 1;
226 height = fInfo->window_bounds.bottom
227 - fInfo->window_bounds.top + 1;
228 }
229
230 if (fColorSpace != colorSpace) {
231 fColorSpace = colorSpace;
232 _SetupRenderBuffer(&fFrontRenderBuffer->Base, fColorSpace);
233 if (fVisual->doubleBufferMode)
234 _SetupRenderBuffer(&fBackRenderBuffer->Base, fColorSpace);
235 }
236
237 _CheckResize(width, height);
238 }
239
240
241 void
242 MesaSoftwareRast::UnlockGL()
243 {
244 CALLED();
245 _mesa_make_current(this, NULL, NULL);
246 BGLRenderer::UnlockGL();
247 }
248
249
250 void
251 MesaSoftwareRast::SwapBuffers(bool VSync)
252 {
253 CALLED();
254
255 if (!fBitmap)
256 return;
257
258 if (fVisual->doubleBufferMode)
259 _mesa_notifySwapBuffers(this);
260
261 if (!fDirectModeEnabled || fInfo == NULL) {
262 if (GLView()->LockLooperWithTimeout(1000) == B_OK) {
263 GLView()->DrawBitmap(fBitmap, B_ORIGIN);
264 GLView()->UnlockLooper();
265 }
266 } else {
267 // TODO: Here the BGLView needs to be drawlocked.
268 _CopyToDirect();
269 }
270
271 if (VSync) {
272 BScreen screen(GLView()->Window());
273 screen.WaitForRetrace();
274 }
275 }
276
277
278 void
279 MesaSoftwareRast::Draw(BRect updateRect)
280 {
281 CALLED();
282 if (fBitmap && (!fDirectModeEnabled || (fInfo == NULL)))
283 GLView()->DrawBitmap(fBitmap, updateRect, updateRect);
284 }
285
286
287 status_t
288 MesaSoftwareRast::CopyPixelsOut(BPoint location, BBitmap* bitmap)
289 {
290 CALLED();
291 color_space scs = fBitmap->ColorSpace();
292 color_space dcs = bitmap->ColorSpace();
293
294 if (scs != dcs && (scs != B_RGBA32 || dcs != B_RGB32)) {
295 fprintf(stderr, "CopyPixelsOut(): incompatible color space: %s != %s\n",
296 color_space_name(scs),
297 color_space_name(dcs));
298 return B_BAD_TYPE;
299 }
300
301 BRect sr = fBitmap->Bounds();
302 BRect dr = bitmap->Bounds();
303
304 sr = sr & dr.OffsetBySelf(location);
305 dr = sr.OffsetByCopy(-location.x, -location.y);
306
307 uint8* ps = (uint8*)fBitmap->Bits();
308 uint8* pd = (uint8*)bitmap->Bits();
309 uint32* s;
310 uint32* d;
311 uint32 y;
312 for (y = (uint32)sr.top; y <= (uint32)sr.bottom; y++) {
313 s = (uint32*)(ps + y * fBitmap->BytesPerRow());
314 s += (uint32)sr.left;
315
316 d = (uint32*)(pd + (y + (uint32)(dr.top - sr.top))
317 * bitmap->BytesPerRow());
318 d += (uint32)dr.left;
319
320 memcpy(d, s, dr.IntegerWidth() * 4);
321 }
322 return B_OK;
323 }
324
325
326 status_t
327 MesaSoftwareRast::CopyPixelsIn(BBitmap* bitmap, BPoint location)
328 {
329 CALLED();
330 color_space scs = bitmap->ColorSpace();
331 color_space dcs = fBitmap->ColorSpace();
332
333 if (scs != dcs && (dcs != B_RGBA32 || scs != B_RGB32)) {
334 fprintf(stderr, "CopyPixelsIn(): incompatible color space: %s != %s\n",
335 color_space_name(scs),
336 color_space_name(dcs));
337 return B_BAD_TYPE;
338 }
339
340 BRect sr = bitmap->Bounds();
341 BRect dr = fBitmap->Bounds();
342
343 sr = sr & dr.OffsetBySelf(location);
344 dr = sr.OffsetByCopy(-location.x, -location.y);
345
346 uint8* ps = (uint8*)bitmap->Bits();
347 uint8* pd = (uint8*)fBitmap->Bits();
348 uint32* s;
349 uint32* d;
350 uint32 y;
351 for (y = (uint32)sr.top; y <= (uint32)sr.bottom; y++) {
352 s = (uint32*)(ps + y * bitmap->BytesPerRow());
353 s += (uint32)sr.left;
354
355 d = (uint32*)(pd + (y + (uint32)(dr.top - sr.top))
356 * fBitmap->BytesPerRow());
357 d += (uint32)dr.left;
358
359 memcpy(d, s, dr.IntegerWidth() * 4);
360 }
361 return B_OK;
362 }
363
364
365 void
366 MesaSoftwareRast::EnableDirectMode(bool enabled)
367 {
368 fDirectModeEnabled = enabled;
369 }
370
371
372 void
373 MesaSoftwareRast::DirectConnected(direct_buffer_info* info)
374 {
375 // TODO: I'm not sure we need to do this: BGLView already
376 // keeps a local copy of the direct_buffer_info passed by
377 // BDirectWindow::DirectConnected().
378 BAutolock lock(fInfoLocker);
379 if (info) {
380 if (!fInfo) {
381 fInfo = (direct_buffer_info*)malloc(DIRECT_BUFFER_INFO_AREA_SIZE);
382 if (!fInfo)
383 return;
384 }
385 memcpy(fInfo, info, DIRECT_BUFFER_INFO_AREA_SIZE);
386 } else if (fInfo) {
387 free(fInfo);
388 fInfo = NULL;
389 }
390 }
391
392
393 void
394 MesaSoftwareRast::FrameResized(float width, float height)
395 {
396 BAutolock lock(fInfoLocker);
397 _CheckResize((GLuint)width, (GLuint)height);
398 }
399
400
401 void
402 MesaSoftwareRast::_CheckResize(GLuint newWidth, GLuint newHeight)
403 {
404 CALLED();
405
406 if (fBitmap && newWidth == fWidth
407 && newHeight == fHeight) {
408 return;
409 }
410
411 _mesa_resize_framebuffer(this, fFrameBuffer, newWidth, newHeight);
412 fHeight = newHeight;
413 fWidth = newWidth;
414
415 _AllocateBitmap();
416 }
417
418
419 void
420 MesaSoftwareRast::_AllocateBitmap()
421 {
422 CALLED();
423
424 // allocate new size of back buffer bitmap
425 delete fBitmap;
426 fBitmap = NULL;
427
428 if (fWidth < 1 || fHeight < 1) {
429 TRACE("%s: Cannot allocate bitmap < 1x1!\n", __func__);
430 return;
431 }
432
433 BRect rect(0.0, 0.0, fWidth - 1, fHeight - 1);
434 fBitmap = new BBitmap(rect, fColorSpace);
435
436 #if 0
437 // Used for platform optimized drawing
438 for (uint i = 0; i < fHeight; i++) {
439 fRowAddr[fHeight - i - 1] = (GLvoid *)((GLubyte *)fBitmap->Bits()
440 + i * fBitmap->BytesPerRow());
441 }
442 #endif
443
444 fFrameBuffer->Width = fWidth;
445 fFrameBuffer->Height = fHeight;
446 TRACE("%s: Bitmap Size: %" B_PRIu32 "\n", __func__, fBitmap->BitsLength());
447
448 fFrontRenderBuffer->Buffer = (GLubyte*)fBitmap->Bits();
449 }
450
451
452 // #pragma mark - static
453
454
455 const GLubyte*
456 MesaSoftwareRast::_GetString(gl_context* ctx, GLenum name)
457 {
458 switch (name) {
459 case GL_VENDOR:
460 return (const GLubyte*) "Mesa Project";
461 case GL_RENDERER:
462 return (const GLubyte*) "Software Rasterizer";
463 default:
464 // Let core library handle all other cases
465 return NULL;
466 }
467 }
468
469
470 void
471 MesaSoftwareRast::_UpdateState(gl_context* ctx, GLuint new_state)
472 {
473 if (!ctx)
474 return;
475
476 CALLED();
477 _swrast_InvalidateState(ctx, new_state);
478 _swsetup_InvalidateState(ctx, new_state);
479 _vbo_InvalidateState(ctx, new_state);
480 _tnl_InvalidateState(ctx, new_state);
481 }
482
483
484 GLboolean
485 MesaSoftwareRast::_RenderBufferStorage(gl_context* ctx,
486 struct gl_renderbuffer* render, GLenum internalFormat,
487 GLuint width, GLuint height)
488 {
489 CALLED();
490
491 render->Width = width;
492 render->Height = height;
493
494 struct swrast_renderbuffer *swRenderBuffer = swrast_renderbuffer(render);
495
496 swRenderBuffer->RowStride = width * _mesa_get_format_bytes(render->Format);
497
498 return GL_TRUE;
499 }
500
501
502 GLboolean
503 MesaSoftwareRast::_RenderBufferStorageMalloc(gl_context* ctx,
504 struct gl_renderbuffer* render, GLenum internalFormat,
505 GLuint width, GLuint height)
506 {
507 CALLED();
508
509 render->Width = width;
510 render->Height = height;
511
512 struct swrast_renderbuffer *swRenderBuffer = swrast_renderbuffer(render);
513
514 if (swRenderBuffer != NULL) {
515 free(swRenderBuffer->Buffer);
516 swRenderBuffer->RowStride
517 = width * _mesa_get_format_bytes(render->Format);
518
519 uint32 size = swRenderBuffer->RowStride * height;
520 TRACE("%s: Allocate %" B_PRIu32 " bytes for RenderBuffer\n",
521 __func__, size);
522 swRenderBuffer->Buffer = (GLubyte*)malloc(size);
523 if (!swRenderBuffer->Buffer) {
524 ERROR("%s: Memory allocation failure!\n", __func__);
525 return GL_FALSE;
526 }
527 } else {
528 ERROR("%s: Couldn't obtain software renderbuffer!\n",
529 __func__);
530 return GL_FALSE;
531 }
532
533 return GL_TRUE;
534 }
535
536
537 void
538 MesaSoftwareRast::_Flush(gl_context* ctx)
539 {
540 CALLED();
541 MesaSoftwareRast* driverContext = static_cast<MesaSoftwareRast*>(ctx);
542
543 //MesaSoftwareRast* driverContext = (MesaSoftwareRast*)ctx->DriverCtx;
544 if ((driverContext->fOptions & BGL_DOUBLE) == 0) {
545 // TODO: SwapBuffers() can call _CopyToDirect(), which should
546 // be always called with with the BGLView drawlocked.
547 // This is not always the case if called from here.
548 driverContext->SwapBuffers();
549 }
550 }
551
552
553 struct swrast_renderbuffer*
554 MesaSoftwareRast::_NewRenderBuffer(bool front)
555 {
556 CALLED();
557 struct swrast_renderbuffer *swRenderBuffer
558 = (struct swrast_renderbuffer*)calloc(1, sizeof *swRenderBuffer);
559
560 if (!swRenderBuffer) {
561 ERROR("%s: Failed calloc RenderBuffer\n", __func__);
562 return NULL;
563 }
564
565 _mesa_init_renderbuffer(&swRenderBuffer->Base, 0);
566
567 swRenderBuffer->Base.ClassID = HAIKU_SWRAST_RENDERBUFFER_CLASS;
568 swRenderBuffer->Base.RefCount = 1;
569 swRenderBuffer->Base.Delete = _RenderBufferDelete;
570
571 if (!front)
572 swRenderBuffer->Base.AllocStorage = _RenderBufferStorageMalloc;
573 else
574 swRenderBuffer->Base.AllocStorage = _RenderBufferStorage;
575
576 if (_SetupRenderBuffer(&swRenderBuffer->Base, fColorSpace) != B_OK) {
577 free(swRenderBuffer);
578 return NULL;
579 }
580
581 return swRenderBuffer;
582 }
583
584
585 status_t
586 MesaSoftwareRast::_SetupRenderBuffer(struct gl_renderbuffer* rb,
587 color_space colorSpace)
588 {
589 CALLED();
590
591 rb->InternalFormat = GL_RGBA;
592
593 switch (colorSpace) {
594 case B_RGBA32:
595 rb->_BaseFormat = GL_RGBA;
596 rb->Format = MESA_FORMAT_B8G8R8A8_UNORM;
597 break;
598 case B_RGB32:
599 rb->_BaseFormat = GL_RGB;
600 rb->Format = MESA_FORMAT_B8G8R8X8_UNORM;
601 break;
602 case B_RGB24:
603 rb->_BaseFormat = GL_RGB;
604 rb->Format = MESA_FORMAT_BGR_UNORM8;
605 break;
606 case B_RGB16:
607 rb->_BaseFormat = GL_RGB;
608 rb->Format = MESA_FORMAT_RGB565;
609 break;
610 case B_RGB15:
611 rb->_BaseFormat = GL_RGB;
612 rb->Format = MESA_FORMAT_ARGB1555;
613 break;
614 default:
615 fprintf(stderr, "Unsupported screen color space %s\n",
616 color_space_name(fColorSpace));
617 debugger("Unsupported OpenGL color space");
618 return B_ERROR;
619 }
620 return B_OK;
621 }
622
623
624 /*! Y inverted Map RenderBuffer function
625 We use a BBitmap for storage which has Y inverted.
626 If the Mesa provided Map function ever allows external
627 control of this we can omit this function.
628 */
629 void
630 MesaSoftwareRast::_RenderBufferMap(gl_context *ctx,
631 struct gl_renderbuffer *rb, GLuint x, GLuint y, GLuint w, GLuint h,
632 GLbitfield mode, GLubyte **mapOut, GLint *rowStrideOut)
633 {
634 if (rb->ClassID == HAIKU_SWRAST_RENDERBUFFER_CLASS) {
635 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
636 const GLuint bpp = _mesa_get_format_bytes(rb->Format);
637 GLint rowStride = rb->Width * bpp; // in Bytes
638
639 y = rb->Height - y - 1;
640
641 *rowStrideOut = -rowStride;
642 *mapOut = (GLubyte *) srb->Buffer + y * rowStride + x * bpp;
643 } else {
644 _swrast_map_soft_renderbuffer(ctx, rb, x, y, w, h, mode,
645 mapOut, rowStrideOut);
646 }
647 }
648
649
650 void
651 MesaSoftwareRast::_RenderBufferDelete(struct gl_context *ctx,
652 struct gl_renderbuffer* rb)
653 {
654 CALLED();
655 if (rb != NULL) {
656 struct swrast_renderbuffer *swRenderBuffer
657 = swrast_renderbuffer(rb);
658 if (swRenderBuffer != NULL)
659 free(swRenderBuffer->Buffer);
660 }
661 free(rb);
662 }
663
664
665 void
666 MesaSoftwareRast::_CopyToDirect()
667 {
668 BAutolock lock(fInfoLocker);
669
670 // check the bitmap size still matches the size
671 if (fInfo->window_bounds.bottom - fInfo->window_bounds.top
672 != fBitmap->Bounds().IntegerHeight()
673 || fInfo->window_bounds.right - fInfo->window_bounds.left
674 != fBitmap->Bounds().IntegerWidth())
675 return;
676
677 uint8 bytesPerPixel = fInfo->bits_per_pixel / 8;
678 uint32 bytesPerRow = fBitmap->BytesPerRow();
679 for (uint32 i = 0; i < fInfo->clip_list_count; i++) {
680 clipping_rect *clip = &fInfo->clip_list[i];
681 int32 height = clip->bottom - clip->top + 1;
682 int32 bytesWidth
683 = (clip->right - clip->left + 1) * bytesPerPixel;
684 uint8* p = (uint8*)fInfo->bits + clip->top
685 * fInfo->bytes_per_row + clip->left * bytesPerPixel;
686 uint8* b = (uint8*)fBitmap->Bits()
687 + (clip->top - fInfo->window_bounds.top) * bytesPerRow
688 + (clip->left - fInfo->window_bounds.left)
689 * bytesPerPixel;
690
691 for (int y = 0; y < height; y++) {
692 memcpy(p, b, bytesWidth);
693 p += fInfo->bytes_per_row;
694 b += bytesPerRow;
695 }
696 }
697 }