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 
_ToBeWin(SDL_Window * window)42 static SDL_INLINE SDL_BWin *_ToBeWin(SDL_Window *window) {
43 	return ((SDL_BWin*)(window->driverdata));
44 }
45 
_GetBeApp()46 static SDL_INLINE SDL_BApp *_GetBeApp() {
47 	return ((SDL_BApp*)be_app);
48 }
49 
BE_CreateWindowFramebuffer(_THIS,SDL_Window * window,Uint32 * format,void ** pixels,int * pitch)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 
BE_UpdateWindowFramebuffer(_THIS,SDL_Window * window,const SDL_Rect * rects,int numrects)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 
BE_DrawThread(void * data)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 
BE_DestroyWindowFramebuffer(_THIS,SDL_Window * window)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
BE_UpdateOnce(SDL_Window * window)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: */
260