1 /* 2 Copyright 2011 Haiku, Inc. All rights reserved. 3 Distributed under the terms of the MIT license. 4 5 Authors: 6 Gerald Zajac 7 */ 8 9 #include "accelerant.h" 10 #include "rage128.h" 11 12 #include <stdlib.h> 13 14 15 16 uint32 17 OverlayCount(const display_mode* mode) 18 { 19 (void)mode; // avoid compiler warning for unused arg 20 21 return 1; 22 } 23 24 25 const uint32* 26 OverlaySupportedSpaces(const display_mode* mode) 27 { 28 (void)mode; // avoid compiler warning for unused arg 29 30 static const uint32 kSupportedSpaces[] = {B_YCbCr422, 0}; 31 32 return kSupportedSpaces; 33 } 34 35 36 uint32 37 OverlaySupportedFeatures(uint32 colorSpace) 38 { 39 (void)colorSpace; // avoid compiler warning for unused arg 40 41 return B_OVERLAY_COLOR_KEY 42 | B_OVERLAY_HORIZONTAL_FILTERING 43 | B_OVERLAY_VERTICAL_FILTERING; 44 } 45 46 47 const overlay_buffer* 48 AllocateOverlayBuffer(color_space colorSpace, uint16 width, uint16 height) 49 { 50 SharedInfo& si = *gInfo.sharedInfo; 51 52 TRACE("AllocateOverlayBuffer() width %u, height %u, colorSpace 0x%lx\n", 53 width, height, colorSpace); 54 55 // If Mach 64 chip, check hardware limits. 56 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))) 62 return NULL; 63 } 64 65 si.overlayLock.Acquire(); 66 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. 72 73 if (colorSpace != B_YCbCr422) { 74 si.overlayLock.Release(); 75 TRACE("AllocateOverlayBuffer() unsupported color space 0x%x\n", 76 colorSpace); 77 return NULL; 78 } 79 80 uint32 bytesPerPixel = 2; // B_YCbCr422 uses 2 bytes per pixel 81 82 // Calculate required buffer size as a multiple of 1K. 83 uint32 buffSize = (width * bytesPerPixel * height + 0x3ff) & ~0x3ff; 84 85 OverlayBuffer* ovBuff = si.overlayBuffer; 86 OverlayBuffer* prevOvBuff = NULL; 87 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 92 // cursor. 93 94 addr_t prevBuffAddr = (si.videoMemAddr + si.cursorOffset - 0xfff) & ~0xfff; 95 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 99 // buffer. 100 101 addr_t currentBuffEndAddr = (addr_t)ovBuff->buffer + ovBuff->size; 102 if ((prevBuffAddr - currentBuffEndAddr) >= buffSize) 103 break; // sufficient space for the new buffer 104 105 prevBuffAddr = (addr_t)ovBuff->buffer; 106 prevOvBuff = ovBuff; 107 ovBuff = ovBuff->nextBuffer; 108 } 109 110 OverlayBuffer* nextOvBuff = ovBuff; 111 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. 118 119 addr_t fbEndAddr = si.videoMemAddr + si.frameBufferOffset 120 + (si.displayMode.virtual_width 121 * ((si.displayMode.bitsPerPixel + 7) / 8) // bytes per pixel 122 * si.displayMode.virtual_height); 123 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 129 } 130 131 nextOvBuff = NULL; 132 } 133 134 ovBuff = (OverlayBuffer*)malloc(sizeof(OverlayBuffer)); 135 if (ovBuff == NULL) { 136 si.overlayLock.Release(); 137 return NULL; // memory not available for OverlayBuffer struct 138 } 139 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)); 149 150 if (prevOvBuff == NULL) 151 si.overlayBuffer = ovBuff; 152 else 153 prevOvBuff->nextBuffer = ovBuff; 154 155 si.overlayLock.Release(); 156 TRACE("AllocateOverlayBuffer() allocated %ld (0x%lx) byte buffer at 0x%lx\n", 157 buffSize, buffSize, ovBuff->buffer); 158 return ovBuff; 159 } 160 161 162 status_t 163 ReleaseOverlayBuffer(const overlay_buffer* buffer) 164 { 165 SharedInfo& si = *gInfo.sharedInfo; 166 167 if (buffer == NULL) 168 return B_BAD_VALUE; 169 170 // Find the buffer to be released. 171 172 OverlayBuffer* ovBuff = si.overlayBuffer; 173 OverlayBuffer* prevOvBuff = NULL; 174 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. 179 180 if (prevOvBuff == NULL) 181 si.overlayBuffer = ovBuff->nextBuffer; 182 else 183 prevOvBuff->nextBuffer = ovBuff->nextBuffer; 184 185 free(ovBuff); 186 return B_OK; 187 } 188 189 prevOvBuff = ovBuff; 190 ovBuff = ovBuff->nextBuffer; 191 } 192 193 TRACE("ReleaseOverlayBuffer() buffer to release at 0x%lx not found\n", 194 buffer->buffer); 195 return B_ERROR; // buffer to be released not found in chain of buffers 196 } 197 198 199 status_t 200 GetOverlayConstraints(const display_mode* mode, const overlay_buffer* buffer, 201 overlay_constraints* constraints) 202 { 203 if ((mode == NULL) || (buffer == NULL) || (constraints == NULL)) 204 return B_ERROR; 205 206 // Position (values are in pixels) 207 constraints->view.h_alignment = 0; 208 constraints->view.v_alignment = 0; 209 210 if (buffer->space == B_YCbCr422) 211 constraints->view.width_alignment = 7; 212 else { 213 TRACE("GetOverlayConstraints() color space 0x%x out of range\n", 214 buffer->space); 215 return B_BAD_VALUE; 216 } 217 218 constraints->view.height_alignment = 0; 219 220 //Size 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; 225 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; 235 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; 240 241 return B_OK; 242 } 243 244 245 overlay_token 246 AllocateOverlay(void) 247 { 248 SharedInfo& si = *gInfo.sharedInfo; 249 250 // There is only a single overlay channel; thus, check if it is already 251 // allocated. 252 253 if (atomic_or(&si.overlayAllocated, 1) != 0) { 254 TRACE("AllocateOverlay() overlay channel already in use\n"); 255 return NULL; 256 } 257 258 return (overlay_token)(addr_t)++si.overlayToken; 259 } 260 261 262 status_t 263 ReleaseOverlay(overlay_token overlayToken) 264 { 265 SharedInfo& si = *gInfo.sharedInfo; 266 267 if (overlayToken != (overlay_token)(addr_t)si.overlayToken) { 268 TRACE("ReleaseOverlay() error - no overlay previously allocated\n"); 269 return B_BAD_VALUE; 270 } 271 272 if (MACH64_FAMILY(si.chipType)) 273 Mach64_StopOverlay(); 274 else 275 Rage128_StopOverlay(); 276 277 atomic_and(&si.overlayAllocated, 0); // mark overlay as unallocated 278 return B_OK; 279 } 280 281 282 status_t 283 ConfigureOverlay(overlay_token overlayToken, const overlay_buffer* buffer, 284 const overlay_window* window, const overlay_view* view) 285 { 286 SharedInfo& si = *gInfo.sharedInfo; 287 288 if (overlayToken != (overlay_token)(addr_t)si.overlayToken) 289 return B_BAD_VALUE; 290 291 if (buffer == NULL) 292 return B_BAD_VALUE; 293 294 if (window == NULL || view == NULL) { 295 if (MACH64_FAMILY(si.chipType)) 296 Mach64_StopOverlay(); 297 else 298 Rage128_StopOverlay(); 299 300 return B_OK; 301 } 302 303 // Program the overlay hardware. 304 if (MACH64_FAMILY(si.chipType)) { 305 if (!Mach64_DisplayOverlay(window, buffer)) { 306 TRACE("ConfigureOverlay(), call to Mach64_DisplayOverlay() " 307 "returned error\n"); 308 return B_ERROR; 309 } 310 } else { 311 if (!Rage128_DisplayOverlay(window, buffer)) { 312 TRACE("ConfigureOverlay(), call to Rage128_DisplayOverlay() " 313 "returned error\n"); 314 return B_ERROR; 315 } 316 } 317 318 return B_OK; 319 } 320