1 /* 2 * Copyright 2010 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 "3dfx.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_RGB16, 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 si.overlayLock.Acquire(); 56 57 // Note: When allocating buffers, buffer allocation starts at the end of 58 // video memory, and works backward to the end of the video frame buffer. 59 // The allocated buffers are recorded in a linked list of OverlayBuffer 60 // objects which are ordered by the buffer address with the first object 61 // in the list having the highest buffer address. 62 63 uint32 bytesPerPixel; 64 65 switch (colorSpace) { 66 case B_YCbCr422: 67 case B_RGB16: 68 bytesPerPixel = 2; 69 break; 70 default: 71 si.overlayLock.Release(); 72 TRACE("AllocateOverlayBuffer() unsupported color space 0x%x\n", 73 colorSpace); 74 return NULL; 75 } 76 77 // Calculate required buffer size as a multiple of 1K. 78 uint32 buffSize = (width * bytesPerPixel * height + 0x3ff) & ~0x3ff; 79 80 // If the buffer area starts at the end of the video memory, the Voodoo5 81 // chip has the following display problems: displays a pink/red band at 82 // the bottom of the overlay display, leaves some artifacts at the top of 83 // screen, and messes up the displayed cursor when a hardware cursor is 84 // used (cursor image is at beginning of video memory). I don't know 85 // whether the Voodoo5 goes beyond the buffer area or whether this is some 86 // sort of memory mapping problem; nevertheless, adding 4k or 8K to the 87 // buffer size solves the problem. Thus, 16K is added to the buffer size. 88 89 if (si.chipType == VOODOO_5) 90 buffSize += 16 * 1024; 91 92 OverlayBuffer* ovBuff = si.overlayBuffer; 93 OverlayBuffer* prevOvBuff = NULL; 94 95 // If no buffers have been allocated, prevBuffAddr calculated here will be 96 // the address where the buffer area will start. 97 98 addr_t prevBuffAddr = si.videoMemAddr + si.frameBufferOffset 99 + si.maxFrameBufferSize; 100 101 while (ovBuff != NULL) { 102 // Test if there is sufficient space between the end of the current 103 // buffer and the start of the previous buffer to allocate the new 104 // buffer. 105 106 addr_t currentBuffEndAddr = (addr_t)ovBuff->buffer + ovBuff->size; 107 if ((prevBuffAddr - currentBuffEndAddr) >= buffSize) 108 break; // sufficient space for the new buffer 109 110 prevBuffAddr = (addr_t)ovBuff->buffer; 111 prevOvBuff = ovBuff; 112 ovBuff = ovBuff->nextBuffer; 113 } 114 115 OverlayBuffer* nextOvBuff = ovBuff; 116 117 if (ovBuff == NULL) { 118 // No space between any current buffers of the required size was found; 119 // thus space must be allocated between the last buffer and the end of 120 // the video frame buffer. Compute where current video frame buffer 121 // ends so that it can be determined if there is sufficient space for 122 // the new buffer to be created. 123 124 addr_t fbEndAddr = si.videoMemAddr + si.frameBufferOffset 125 + (si.displayMode.virtual_width * si.displayMode.bytesPerPixel 126 * si.displayMode.virtual_height); 127 128 if (buffSize > prevBuffAddr - fbEndAddr) { 129 si.overlayLock.Release(); 130 TRACE("AllocateOverlayBuffer() insuffcient space for %ld (0x%lx) " 131 "byte buffer\n", buffSize, buffSize); 132 return NULL; // insufficient space for buffer 133 } 134 135 nextOvBuff = NULL; 136 } 137 138 ovBuff = (OverlayBuffer*)malloc(sizeof(OverlayBuffer)); 139 if (ovBuff == NULL) { 140 si.overlayLock.Release(); 141 return NULL; // memory not available for OverlayBuffer struct 142 } 143 144 ovBuff->nextBuffer = nextOvBuff; 145 ovBuff->size = buffSize; 146 ovBuff->space = colorSpace; 147 ovBuff->width = width; 148 ovBuff->height = height; 149 ovBuff->bytes_per_row = width * bytesPerPixel; 150 ovBuff->buffer = (void*)(prevBuffAddr - buffSize); 151 ovBuff->buffer_dma = (void*)(si.videoMemPCI 152 + ((addr_t)ovBuff->buffer - si.videoMemAddr)); 153 154 if (prevOvBuff == NULL) 155 si.overlayBuffer = ovBuff; 156 else 157 prevOvBuff->nextBuffer = ovBuff; 158 159 si.overlayLock.Release(); 160 TRACE("AllocateOverlayBuffer() allocated %ld (0x%lx) byte buffer at 0x%lx\n", 161 buffSize, buffSize, ovBuff->buffer); 162 return ovBuff; 163 } 164 165 166 status_t 167 ReleaseOverlayBuffer(const overlay_buffer* buffer) 168 { 169 SharedInfo& si = *gInfo.sharedInfo; 170 171 TRACE("ReleaseOverlayBuffer() called\n"); 172 173 if (buffer == NULL) 174 return B_BAD_VALUE; 175 176 // Find the buffer to be released. 177 178 OverlayBuffer* ovBuff = si.overlayBuffer; 179 OverlayBuffer* prevOvBuff = NULL; 180 181 while (ovBuff != NULL) { 182 if (ovBuff->buffer == buffer->buffer) { 183 // Buffer to be released has been found. Remove the OverlayBuffer 184 // object from the chain of overlay buffers. 185 186 if (prevOvBuff == NULL) 187 si.overlayBuffer = ovBuff->nextBuffer; 188 else 189 prevOvBuff->nextBuffer = ovBuff->nextBuffer; 190 191 free(ovBuff); 192 TRACE("ReleaseOverlayBuffer() return OK\n"); 193 return B_OK; 194 } 195 196 prevOvBuff = ovBuff; 197 ovBuff = ovBuff->nextBuffer; 198 } 199 200 return B_ERROR; // buffer to be released not found in chain of buffers 201 } 202 203 204 status_t 205 GetOverlayConstraints(const display_mode* mode, const overlay_buffer* buffer, 206 overlay_constraints* constraints) 207 { 208 if ((mode == NULL) || (buffer == NULL) || (constraints == NULL)) 209 return B_ERROR; 210 211 // Position (values are in pixels) 212 constraints->view.h_alignment = 0; 213 constraints->view.v_alignment = 0; 214 215 switch (buffer->space) { 216 case B_YCbCr422: 217 case B_RGB16: 218 constraints->view.width_alignment = 7; 219 break; 220 default: 221 TRACE("GetOverlayConstraints() color space 0x%x out of range\n", 222 buffer->space); 223 return B_BAD_VALUE; 224 } 225 226 constraints->view.height_alignment = 0; 227 228 //Size 229 constraints->view.width.min = 4; 230 constraints->view.height.min = 4; 231 constraints->view.width.max = buffer->width; 232 constraints->view.height.max = buffer->height; 233 234 // Scaler output restrictions 235 constraints->window.h_alignment = 0; 236 constraints->window.v_alignment = 0; 237 constraints->window.width_alignment = 0; 238 constraints->window.height_alignment = 0; 239 constraints->window.width.min = 2; 240 constraints->window.width.max = mode->virtual_width; 241 constraints->window.height.min = 2; 242 constraints->window.height.max = mode->virtual_height; 243 244 constraints->h_scale.min = 1.0; 245 constraints->h_scale.max = 8.0; 246 constraints->v_scale.min = 1.0; 247 constraints->v_scale.max = 8.0; 248 249 return B_OK; 250 } 251 252 253 overlay_token 254 AllocateOverlay(void) 255 { 256 SharedInfo& si = *gInfo.sharedInfo; 257 258 TRACE("AllocateOverlay() called\n"); 259 260 // There is only a single overlay channel; thus, check if it is already 261 // allocated. 262 263 if (atomic_or(&si.overlayAllocated, 1) != 0) { 264 TRACE("AllocateOverlay() overlay channel already in use\n"); 265 return NULL; 266 } 267 TRACE("AllocateOverlay() Overlay allocated, overlayToken: %d\n", 268 si.overlayToken); 269 return (overlay_token)++si.overlayToken; 270 } 271 272 273 status_t 274 ReleaseOverlay(overlay_token overlayToken) 275 { 276 SharedInfo& si = *gInfo.sharedInfo; 277 278 TRACE("ReleaseOverlay() called\n"); 279 280 if (overlayToken != (overlay_token)si.overlayToken) 281 return B_BAD_VALUE; 282 283 TDFX_StopOverlay(); 284 285 atomic_and(&si.overlayAllocated, 0); // mark overlay as unallocated 286 287 TRACE("ReleaseOverlay() return OK\n"); 288 return B_OK; 289 } 290 291 292 status_t 293 ConfigureOverlay (overlay_token overlayToken, const overlay_buffer* buffer, 294 const overlay_window* window, const overlay_view* view) 295 { 296 SharedInfo& si = *gInfo.sharedInfo; 297 298 if (overlayToken != (overlay_token)si.overlayToken) 299 return B_BAD_VALUE; 300 301 if (buffer == NULL) 302 return B_BAD_VALUE; 303 304 if (window == NULL || view == NULL) { 305 TDFX_StopOverlay(); 306 TRACE("ConfigureOverlay() hide only\n"); 307 return B_OK; 308 } 309 310 // Program the overlay hardware. 311 if (!TDFX_DisplayOverlay(window, buffer, view)) { 312 TRACE("ConfigureOverlay(), call to TDFX_DisplayOverlay() returned error\n"); 313 return B_ERROR; 314 } 315 316 return B_OK; 317 } 318