f53c500195faa5dd4d82b058b6465df377f6ed34
[platform/upstream/SDL.git] / src / video / haiku / SDL_bframebuffer.cc
1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2018 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 #ifndef DRAWTHREAD
39 static int32 BE_UpdateOnce(SDL_Window *window);
40 #endif
41
42 static SDL_INLINE SDL_BWin *_ToBeWin(SDL_Window *window) {
43         return ((SDL_BWin*)(window->driverdata));
44 }
45
46 static SDL_INLINE SDL_BApp *_GetBeApp() {
47         return ((SDL_BApp*)be_app);
48 }
49
50 int BE_CreateWindowFramebuffer(_THIS, SDL_Window * window,
51                                        Uint32 * format,
52                                        void ** pixels, int *pitch) {
53         SDL_BWin *bwin = _ToBeWin(window);
54         BScreen bscreen;
55         if(!bscreen.IsValid()) {
56                 return -1;
57         }
58
59         while(!bwin->Connected()) { snooze(100); }
60         
61         /* Make sure we have exclusive access to frame buffer data */
62         bwin->LockBuffer();
63
64         /* format */
65         display_mode bmode;
66         bscreen.GetMode(&bmode);
67         int32 bpp = BE_ColorSpaceToBitsPerPixel(bmode.space);
68         *format = BE_BPPToSDLPxFormat(bpp);
69
70         /* Create the new bitmap object */
71         BBitmap *bitmap = bwin->GetBitmap();
72
73         if(bitmap) {
74                 delete bitmap;
75         }
76         bitmap = new BBitmap(bwin->Bounds(), (color_space)bmode.space,
77                         false,  /* Views not accepted */
78                         true);  /* Contiguous memory required */
79                         
80         if(bitmap->InitCheck() != B_OK) {
81                 delete bitmap;
82                 return SDL_SetError("Could not initialize back buffer!");
83         }
84
85
86         bwin->SetBitmap(bitmap);
87         
88         /* Set the pixel pointer */
89         *pixels = bitmap->Bits();
90
91         /* pitch = width of window, in bytes */
92         *pitch = bitmap->BytesPerRow();
93
94         bwin->SetBufferExists(true);
95         bwin->SetTrashBuffer(false);
96         bwin->UnlockBuffer();
97         return 0;
98 }
99
100
101
102 int BE_UpdateWindowFramebuffer(_THIS, SDL_Window * window,
103                                       const SDL_Rect * rects, int numrects) {
104         if(!window)
105                 return 0;
106
107         SDL_BWin *bwin = _ToBeWin(window);
108
109 #ifdef DRAWTHREAD       
110         bwin->LockBuffer();
111         bwin->SetBufferDirty(true);
112         bwin->UnlockBuffer();
113 #else
114         bwin->SetBufferDirty(true);
115         BE_UpdateOnce(window);
116 #endif
117
118         return 0;
119 }
120
121 int32 BE_DrawThread(void *data) {
122         SDL_BWin *bwin = (SDL_BWin*)data;
123         
124         BScreen bscreen;
125         if(!bscreen.IsValid()) {
126                 return -1;
127         }
128
129         while(bwin->ConnectionEnabled()) {
130                 if( bwin->Connected() && bwin->BufferExists() && bwin->BufferIsDirty() ) {
131                         bwin->LockBuffer();
132                         BBitmap *bitmap = NULL;
133                         bitmap = bwin->GetBitmap();
134                         int32 windowPitch = bitmap->BytesPerRow();
135                         int32 bufferPitch = bwin->GetRowBytes();
136                         uint8 *windowpx;
137                         uint8 *bufferpx;
138
139                         int32 BPP = bwin->GetBytesPerPx();
140                         int32 windowSub = bwin->GetFbX() * BPP +
141                                                   bwin->GetFbY() * windowPitch;
142                         clipping_rect *clips = bwin->GetClips();
143                         int32 numClips = bwin->GetNumClips();
144                         int i, y;
145
146                         /* Blit each clipping rectangle */
147                         bscreen.WaitForRetrace();
148                         for(i = 0; i < numClips; ++i) {
149                                 /* Get addresses of the start of each clipping rectangle */
150                                 int32 width = clips[i].right - clips[i].left + 1;
151                                 int32 height = clips[i].bottom - clips[i].top + 1;
152                                 bufferpx = bwin->GetBufferPx() + 
153                                         clips[i].top * bufferPitch + clips[i].left * BPP;
154                                 windowpx = (uint8*)bitmap->Bits() + 
155                                         clips[i].top * windowPitch + clips[i].left * BPP -
156                                         windowSub;
157
158                                 /* Copy each row of pixels from the window buffer into the frame
159                                    buffer */
160                                 for(y = 0; y < height; ++y)
161                                 {
162
163                                         if(bwin->CanTrashWindowBuffer()) {
164                                                 goto escape;    /* Break out before the buffer is killed */
165                                         }
166
167                                         memcpy(bufferpx, windowpx, width * BPP);
168                                         bufferpx += bufferPitch;
169                                         windowpx += windowPitch;
170                                 }
171                         }
172
173                         bwin->SetBufferDirty(false);
174 escape:
175                         bwin->UnlockBuffer();
176                 } else {
177                         snooze(16000);
178                 }
179         }
180         
181         return B_OK;
182 }
183
184 void BE_DestroyWindowFramebuffer(_THIS, SDL_Window * window) {
185         SDL_BWin *bwin = _ToBeWin(window);
186         
187         bwin->LockBuffer();
188         
189         /* Free and clear the window buffer */
190         BBitmap *bitmap = bwin->GetBitmap();
191         delete bitmap;
192         bwin->SetBitmap(NULL);
193         bwin->SetBufferExists(false);
194         bwin->UnlockBuffer();
195 }
196
197
198 /*
199  * TODO:
200  * This was written to test if certain errors were caused by threading issues.
201  * The specific issues have since become rare enough that they may have been
202  * solved, but I doubt it- they were pretty sporadic before now.
203  */
204 #ifndef DRAWTHREAD
205 static int32 BE_UpdateOnce(SDL_Window *window) {
206         SDL_BWin *bwin = _ToBeWin(window);
207         BScreen bscreen;
208         if(!bscreen.IsValid()) {
209                 return -1;
210         }
211
212         if(bwin->ConnectionEnabled() && bwin->Connected()) {
213                 bwin->LockBuffer();
214                 int32 windowPitch = window->surface->pitch;
215                 int32 bufferPitch = bwin->GetRowBytes();
216                 uint8 *windowpx;
217                 uint8 *bufferpx;
218
219                 int32 BPP = bwin->GetBytesPerPx();
220                 uint8 *windowBaseAddress = (uint8*)window->surface->pixels;
221                 int32 windowSub = bwin->GetFbX() * BPP +
222                                                   bwin->GetFbY() * windowPitch;
223                 clipping_rect *clips = bwin->GetClips();
224                 int32 numClips = bwin->GetNumClips();
225                 int i, y;
226
227                 /* Blit each clipping rectangle */
228                 bscreen.WaitForRetrace();
229                 for(i = 0; i < numClips; ++i) {
230                         /* Get addresses of the start of each clipping rectangle */
231                         int32 width = clips[i].right - clips[i].left + 1;
232                         int32 height = clips[i].bottom - clips[i].top + 1;
233                         bufferpx = bwin->GetBufferPx() + 
234                                 clips[i].top * bufferPitch + clips[i].left * BPP;
235                         windowpx = windowBaseAddress + 
236                                 clips[i].top * windowPitch + clips[i].left * BPP - windowSub;
237
238                         /* Copy each row of pixels from the window buffer into the frame
239                            buffer */
240                         for(y = 0; y < height; ++y)
241                         {
242                                 memcpy(bufferpx, windowpx, width * BPP);
243                                 bufferpx += bufferPitch;
244                                 windowpx += windowPitch;
245                         }
246                 }
247                 bwin->UnlockBuffer();
248         }
249         return 0;
250 }
251 #endif
252
253 #ifdef __cplusplus
254 }
255 #endif
256
257 #endif /* SDL_VIDEO_DRIVER_HAIKU */
258
259 /* vi: set ts=4 sw=4 expandtab: */