2 Copyright 2011 Haiku, Inc. All rights reserved.
3 Distributed under the terms of the MIT license.
9 #include "accelerant.h"
17 OverlayCount(const display_mode
* mode
)
19 (void)mode
; // avoid compiler warning for unused arg
26 OverlaySupportedSpaces(const display_mode
* mode
)
28 (void)mode
; // avoid compiler warning for unused arg
30 static const uint32 kSupportedSpaces
[] = {B_YCbCr422
, 0};
32 return kSupportedSpaces
;
37 OverlaySupportedFeatures(uint32 colorSpace
)
39 (void)colorSpace
; // avoid compiler warning for unused arg
41 return B_OVERLAY_COLOR_KEY
42 | B_OVERLAY_HORIZONTAL_FILTERING
43 | B_OVERLAY_VERTICAL_FILTERING
;
48 AllocateOverlayBuffer(color_space colorSpace
, uint16 width
, uint16 height
)
50 SharedInfo
& si
= *gInfo
.sharedInfo
;
52 TRACE("AllocateOverlayBuffer() width %u, height %u, colorSpace 0x%lx\n",
53 width
, height
, colorSpace
);
55 // If Mach 64 chip, check hardware limits.
57 if (MACH64_FAMILY(si
.chipType
)) {
58 if (height
> 2048 || width
> 768
59 || (width
> 384 && si
.chipType
< MACH64_264VTB
)
60 || (width
> 720 && (si
.chipType
< MACH64_264GTPRO
61 || si
.chipType
> MACH64_264LTPRO
)))
65 si
.overlayLock
.Acquire();
67 // Note: When allocating buffers, buffer allocation starts at the end of
68 // video memory, and works backward to the end of the video frame buffer.
69 // The allocated buffers are recorded in a linked list of OverlayBuffer
70 // objects which are ordered by the buffer address with the first object
71 // in the list having the highest buffer address.
73 if (colorSpace
!= B_YCbCr422
) {
74 si
.overlayLock
.Release();
75 TRACE("AllocateOverlayBuffer() unsupported color space 0x%x\n",
80 uint32 bytesPerPixel
= 2; // B_YCbCr422 uses 2 bytes per pixel
82 // Calculate required buffer size as a multiple of 1K.
83 uint32 buffSize
= (width
* bytesPerPixel
* height
+ 0x3ff) & ~0x3ff;
85 OverlayBuffer
* ovBuff
= si
.overlayBuffer
;
86 OverlayBuffer
* prevOvBuff
= NULL
;
88 // If no buffers have been allocated, prevBuffAddr calculated here will be
89 // the address where the buffer area will start. Leave a gap of about 4K
90 // between where the overlay buffers will start and the cursor image;
91 // thus, if the overlay buffer overflows it will be less apt to affect the
94 uint32 prevBuffAddr
= (si
.videoMemAddr
+ si
.cursorOffset
- 0xfff) & ~0xfff;
96 while (ovBuff
!= NULL
) {
97 // Test if there is sufficient space between the end of the current
98 // buffer and the start of the previous buffer to allocate the new
101 uint32 currentBuffEndAddr
= (addr_t
)ovBuff
->buffer
+ ovBuff
->size
;
102 if ((prevBuffAddr
- currentBuffEndAddr
) >= buffSize
)
103 break; // sufficient space for the new buffer
105 prevBuffAddr
= (uint32
)ovBuff
->buffer
;
107 ovBuff
= ovBuff
->nextBuffer
;
110 OverlayBuffer
* nextOvBuff
= ovBuff
;
112 if (ovBuff
== NULL
) {
113 // No space between any current buffers of the required size was found;
114 // thus space must be allocated between the last buffer and the end of
115 // the video frame buffer. Compute where current video frame buffer
116 // ends so that it can be determined if there is sufficient space for
117 // the new buffer to be created.
119 uint32 fbEndAddr
= si
.videoMemAddr
+ si
.frameBufferOffset
120 + (si
.displayMode
.virtual_width
121 * ((si
.displayMode
.bitsPerPixel
+ 7) / 8) // bytes per pixel
122 * si
.displayMode
.virtual_height
);
124 if (buffSize
> prevBuffAddr
- fbEndAddr
) {
125 si
.overlayLock
.Release();
126 TRACE("AllocateOverlayBuffer() insuffcient space for %ld (0x%lx) "
127 "byte buffer\n", buffSize
, buffSize
);
128 return NULL
; // insufficient space for buffer
134 ovBuff
= (OverlayBuffer
*)malloc(sizeof(OverlayBuffer
));
135 if (ovBuff
== NULL
) {
136 si
.overlayLock
.Release();
137 return NULL
; // memory not available for OverlayBuffer struct
140 ovBuff
->nextBuffer
= nextOvBuff
;
141 ovBuff
->size
= buffSize
;
142 ovBuff
->space
= colorSpace
;
143 ovBuff
->width
= width
;
144 ovBuff
->height
= height
;
145 ovBuff
->bytes_per_row
= width
* bytesPerPixel
;
146 ovBuff
->buffer
= (void*)(prevBuffAddr
- buffSize
);
147 ovBuff
->buffer_dma
= (void*)(si
.videoMemPCI
148 + ((addr_t
)ovBuff
->buffer
- si
.videoMemAddr
));
150 if (prevOvBuff
== NULL
)
151 si
.overlayBuffer
= ovBuff
;
153 prevOvBuff
->nextBuffer
= ovBuff
;
155 si
.overlayLock
.Release();
156 TRACE("AllocateOverlayBuffer() allocated %ld (0x%lx) byte buffer at 0x%lx\n",
157 buffSize
, buffSize
, ovBuff
->buffer
);
163 ReleaseOverlayBuffer(const overlay_buffer
* buffer
)
165 SharedInfo
& si
= *gInfo
.sharedInfo
;
170 // Find the buffer to be released.
172 OverlayBuffer
* ovBuff
= si
.overlayBuffer
;
173 OverlayBuffer
* prevOvBuff
= NULL
;
175 while (ovBuff
!= NULL
) {
176 if (ovBuff
->buffer
== buffer
->buffer
) {
177 // Buffer to be released has been found. Remove the OverlayBuffer
178 // object from the chain of overlay buffers.
180 if (prevOvBuff
== NULL
)
181 si
.overlayBuffer
= ovBuff
->nextBuffer
;
183 prevOvBuff
->nextBuffer
= ovBuff
->nextBuffer
;
190 ovBuff
= ovBuff
->nextBuffer
;
193 TRACE("ReleaseOverlayBuffer() buffer to release at 0x%lx not found\n",
195 return B_ERROR
; // buffer to be released not found in chain of buffers
200 GetOverlayConstraints(const display_mode
* mode
, const overlay_buffer
* buffer
,
201 overlay_constraints
* constraints
)
203 if ((mode
== NULL
) || (buffer
== NULL
) || (constraints
== NULL
))
206 // Position (values are in pixels)
207 constraints
->view
.h_alignment
= 0;
208 constraints
->view
.v_alignment
= 0;
210 if (buffer
->space
== B_YCbCr422
)
211 constraints
->view
.width_alignment
= 7;
213 TRACE("GetOverlayConstraints() color space 0x%x out of range\n",
218 constraints
->view
.height_alignment
= 0;
221 constraints
->view
.width
.min
= 4;
222 constraints
->view
.height
.min
= 4;
223 constraints
->view
.width
.max
= buffer
->width
;
224 constraints
->view
.height
.max
= buffer
->height
;
226 // Scaler output restrictions
227 constraints
->window
.h_alignment
= 0;
228 constraints
->window
.v_alignment
= 0;
229 constraints
->window
.width_alignment
= 0;
230 constraints
->window
.height_alignment
= 0;
231 constraints
->window
.width
.min
= 2;
232 constraints
->window
.width
.max
= mode
->virtual_width
;
233 constraints
->window
.height
.min
= 2;
234 constraints
->window
.height
.max
= mode
->virtual_height
;
236 constraints
->h_scale
.min
= 1.0;
237 constraints
->h_scale
.max
= 8.0;
238 constraints
->v_scale
.min
= 1.0;
239 constraints
->v_scale
.max
= 8.0;
246 AllocateOverlay(void)
248 SharedInfo
& si
= *gInfo
.sharedInfo
;
250 // There is only a single overlay channel; thus, check if it is already
253 if (atomic_or(&si
.overlayAllocated
, 1) != 0) {
254 TRACE("AllocateOverlay() overlay channel already in use\n");
258 return (overlay_token
)++si
.overlayToken
;
263 ReleaseOverlay(overlay_token overlayToken
)
265 SharedInfo
& si
= *gInfo
.sharedInfo
;
267 if (overlayToken
!= (overlay_token
)si
.overlayToken
) {
268 TRACE("ReleaseOverlay() error - no overlay previously allocated\n");
272 if (MACH64_FAMILY(si
.chipType
))
273 Mach64_StopOverlay();
275 Rage128_StopOverlay();
277 atomic_and(&si
.overlayAllocated
, 0); // mark overlay as unallocated
283 ConfigureOverlay(overlay_token overlayToken
, const overlay_buffer
* buffer
,
284 const overlay_window
* window
, const overlay_view
* view
)
286 SharedInfo
& si
= *gInfo
.sharedInfo
;
288 if (overlayToken
!= (overlay_token
)si
.overlayToken
)
294 if (window
== NULL
|| view
== NULL
) {
295 if (MACH64_FAMILY(si
.chipType
))
296 Mach64_StopOverlay();
298 Rage128_StopOverlay();
303 // Program the overlay hardware.
304 if (MACH64_FAMILY(si
.chipType
)) {
305 if (!Mach64_DisplayOverlay(window
, buffer
)) {
306 TRACE("ConfigureOverlay(), call to Mach64_DisplayOverlay() "
311 if (!Rage128_DisplayOverlay(window
, buffer
)) {
312 TRACE("ConfigureOverlay(), call to Rage128_DisplayOverlay() "