5e6a300e8e25126c2efea5ab4dff3141783ba048
[platform/upstream/SDL.git] / src / video / haiku / SDL_bframebuffer.cc
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
4
5   This software is provided 'as-is', without any express or implied
6   warranty.  In no event will the authors be held liable for any damages
7   arising from the use of this software.
8
9   Permission is granted to anyone to use this software for any purpose,
10   including commercial applications, and to alter it and redistribute it
11   freely, subject to the following restrictions:
12
13   1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17   2. Altered source versions must be plainly marked as such, and must not be
18      misrepresented as being the original software.
19   3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22
23 #if SDL_VIDEO_DRIVER_HAIKU
24
25 #include "SDL_bframebuffer.h"
26
27 #include <AppKit.h>
28 #include <InterfaceKit.h>
29 #include "SDL_bmodes.h"
30 #include "SDL_BWin.h"
31
32 #include "../../main/haiku/SDL_BApp.h"
33
34 #ifdef __cplusplus
35 extern "C" {
36 #endif
37
38 int32 BE_UpdateOnce(SDL_Window *window);
39
40 static SDL_INLINE SDL_BWin *_ToBeWin(SDL_Window *window) {
41         return ((SDL_BWin*)(window->driverdata));
42 }
43
44 static SDL_INLINE SDL_BApp *_GetBeApp() {
45         return ((SDL_BApp*)be_app);
46 }
47
48 int BE_CreateWindowFramebuffer(_THIS, SDL_Window * window,
49                                        Uint32 * format,
50                                        void ** pixels, int *pitch) {
51         SDL_BWin *bwin = _ToBeWin(window);
52         BScreen bscreen;
53         if(!bscreen.IsValid()) {
54                 return -1;
55         }
56
57         while(!bwin->Connected()) { snooze(100); }
58         
59         /* Make sure we have exclusive access to frame buffer data */
60         bwin->LockBuffer();
61
62         /* format */
63         display_mode bmode;
64         bscreen.GetMode(&bmode);
65         int32 bpp = BE_ColorSpaceToBitsPerPixel(bmode.space);
66         *format = BE_BPPToSDLPxFormat(bpp);
67
68         /* Create the new bitmap object */
69         BBitmap *bitmap = bwin->GetBitmap();
70
71         if(bitmap) {
72                 delete bitmap;
73         }
74         bitmap = new BBitmap(bwin->Bounds(), (color_space)bmode.space,
75                         false,  /* Views not accepted */
76                         true);  /* Contiguous memory required */
77                         
78         if(bitmap->InitCheck() != B_OK) {
79                 return SDL_SetError("Could not initialize back buffer!\n");
80         }
81
82
83         bwin->SetBitmap(bitmap);
84         
85         /* Set the pixel pointer */
86         *pixels = bitmap->Bits();
87
88         /* pitch = width of window, in bytes */
89         *pitch = bitmap->BytesPerRow();
90
91         bwin->SetBufferExists(true);
92         bwin->SetTrashBuffer(false);
93         bwin->UnlockBuffer();
94         return 0;
95 }
96
97
98
99 int BE_UpdateWindowFramebuffer(_THIS, SDL_Window * window,
100                                       const SDL_Rect * rects, int numrects) {
101         if(!window)
102                 return 0;
103
104         SDL_BWin *bwin = _ToBeWin(window);
105
106 #ifdef DRAWTHREAD       
107         bwin->LockBuffer();
108         bwin->SetBufferDirty(true);
109         bwin->UnlockBuffer();
110 #else
111         bwin->SetBufferDirty(true);
112         BE_UpdateOnce(window);
113 #endif
114
115         return 0;
116 }
117
118 int32 BE_DrawThread(void *data) {
119         SDL_BWin *bwin = (SDL_BWin*)data;
120         
121         BScreen bscreen;
122         if(!bscreen.IsValid()) {
123                 return -1;
124         }
125
126         while(bwin->ConnectionEnabled()) {
127                 if( bwin->Connected() && bwin->BufferExists() && bwin->BufferIsDirty() ) {
128                         bwin->LockBuffer();
129                         BBitmap *bitmap = NULL;
130                         bitmap = bwin->GetBitmap();
131                         int32 windowPitch = bitmap->BytesPerRow();
132                         int32 bufferPitch = bwin->GetRowBytes();
133                         uint8 *windowpx;
134                         uint8 *bufferpx;
135
136                         int32 BPP = bwin->GetBytesPerPx();
137                         int32 windowSub = bwin->GetFbX() * BPP +
138                                                   bwin->GetFbY() * windowPitch;
139                         clipping_rect *clips = bwin->GetClips();
140                         int32 numClips = bwin->GetNumClips();
141                         int i, y;
142
143                         /* Blit each clipping rectangle */
144                         bscreen.WaitForRetrace();
145                         for(i = 0; i < numClips; ++i) {
146                                 clipping_rect rc = clips[i];
147                                 /* Get addresses of the start of each clipping rectangle */
148                                 int32 width = clips[i].right - clips[i].left + 1;
149                                 int32 height = clips[i].bottom - clips[i].top + 1;
150                                 bufferpx = bwin->GetBufferPx() + 
151                                         clips[i].top * bufferPitch + clips[i].left * BPP;
152                                 windowpx = (uint8*)bitmap->Bits() + 
153                                         clips[i].top * windowPitch + clips[i].left * BPP -
154                                         windowSub;
155
156                                 /* Copy each row of pixels from the window buffer into the frame
157                                    buffer */
158                                 for(y = 0; y < height; ++y)
159                                 {
160
161                                         if(bwin->CanTrashWindowBuffer()) {
162                                                 goto escape;    /* Break out before the buffer is killed */
163                                         }
164
165                                         memcpy(bufferpx, windowpx, width * BPP);
166                                         bufferpx += bufferPitch;
167                                         windowpx += windowPitch;
168                                 }
169                         }
170
171                         bwin->SetBufferDirty(false);
172 escape:
173                         bwin->UnlockBuffer();
174                 } else {
175                         snooze(16000);
176                 }
177         }
178         
179         return B_OK;
180 }
181
182 void BE_DestroyWindowFramebuffer(_THIS, SDL_Window * window) {
183         SDL_BWin *bwin = _ToBeWin(window);
184         
185         bwin->LockBuffer();
186         
187         /* Free and clear the window buffer */
188         BBitmap *bitmap = bwin->GetBitmap();
189         delete bitmap;
190         bwin->SetBitmap(NULL);
191         bwin->SetBufferExists(false);
192         bwin->UnlockBuffer();
193 }
194
195
196 /*
197  * TODO:
198  * This was written to test if certain errors were caused by threading issues.
199  * The specific issues have since become rare enough that they may have been
200  * solved, but I doubt it- they were pretty sporadic before now.
201  */
202 int32 BE_UpdateOnce(SDL_Window *window) {
203         SDL_BWin *bwin = _ToBeWin(window);
204         BScreen bscreen;
205         if(!bscreen.IsValid()) {
206                 return -1;
207         }
208
209         if(bwin->ConnectionEnabled() && bwin->Connected()) {
210                 bwin->LockBuffer();
211                 int32 windowPitch = window->surface->pitch;
212                 int32 bufferPitch = bwin->GetRowBytes();
213                 uint8 *windowpx;
214                 uint8 *bufferpx;
215
216                 int32 BPP = bwin->GetBytesPerPx();
217                 uint8 *windowBaseAddress = (uint8*)window->surface->pixels;
218                 int32 windowSub = bwin->GetFbX() * BPP +
219                                                   bwin->GetFbY() * windowPitch;
220                 clipping_rect *clips = bwin->GetClips();
221                 int32 numClips = bwin->GetNumClips();
222                 int i, y;
223
224                 /* Blit each clipping rectangle */
225                 bscreen.WaitForRetrace();
226                 for(i = 0; i < numClips; ++i) {
227                         clipping_rect rc = clips[i];
228                         /* Get addresses of the start of each clipping rectangle */
229                         int32 width = clips[i].right - clips[i].left + 1;
230                         int32 height = clips[i].bottom - clips[i].top + 1;
231                         bufferpx = bwin->GetBufferPx() + 
232                                 clips[i].top * bufferPitch + clips[i].left * BPP;
233                         windowpx = windowBaseAddress + 
234                                 clips[i].top * windowPitch + clips[i].left * BPP - windowSub;
235
236                         /* Copy each row of pixels from the window buffer into the frame
237                            buffer */
238                         for(y = 0; y < height; ++y)
239                         {
240                                 memcpy(bufferpx, windowpx, width * BPP);
241                                 bufferpx += bufferPitch;
242                                 windowpx += windowPitch;
243                         }
244                 }
245                 bwin->UnlockBuffer();
246         }
247         return 0;
248 }
249
250 #ifdef __cplusplus
251 }
252 #endif
253
254 #endif /* SDL_VIDEO_DRIVER_HAIKU */