vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / 3dfx / overlay.cpp
blobca5d711cd436efa1c8cb4cb1cfb99e54d43ae1d5
1 /*
2 * Copyright 2010 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
5 * Authors:
6 * Gerald Zajac
7 */
9 #include "accelerant.h"
10 #include "3dfx.h"
12 #include <stdlib.h>
16 uint32
17 OverlayCount(const display_mode *mode)
19 (void)mode; // avoid compiler warning for unused arg
21 return 1;
25 const uint32*
26 OverlaySupportedSpaces(const display_mode* mode)
28 (void)mode; // avoid compiler warning for unused arg
30 static const uint32 kSupportedSpaces[] = {B_RGB16, B_YCbCr422, 0};
32 return kSupportedSpaces;
36 uint32
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;
47 const overlay_buffer*
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 si.overlayLock.Acquire();
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.
63 uint32 bytesPerPixel;
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;
77 // Calculate required buffer size as a multiple of 1K.
78 uint32 buffSize = (width * bytesPerPixel * height + 0x3ff) & ~0x3ff;
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.
89 if (si.chipType == VOODOO_5)
90 buffSize += 16 * 1024;
92 OverlayBuffer* ovBuff = si.overlayBuffer;
93 OverlayBuffer* prevOvBuff = NULL;
95 // If no buffers have been allocated, prevBuffAddr calculated here will be
96 // the address where the buffer area will start.
98 uint32 prevBuffAddr = si.videoMemAddr + si.frameBufferOffset
99 + si.maxFrameBufferSize;
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.
106 uint32 currentBuffEndAddr = (addr_t)ovBuff->buffer + ovBuff->size;
107 if ((prevBuffAddr - currentBuffEndAddr) >= buffSize)
108 break; // sufficient space for the new buffer
110 prevBuffAddr = (uint32)ovBuff->buffer;
111 prevOvBuff = ovBuff;
112 ovBuff = ovBuff->nextBuffer;
115 OverlayBuffer* nextOvBuff = ovBuff;
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.
124 uint32 fbEndAddr = si.videoMemAddr + si.frameBufferOffset
125 + (si.displayMode.virtual_width * si.displayMode.bytesPerPixel
126 * si.displayMode.virtual_height);
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
135 nextOvBuff = NULL;
138 ovBuff = (OverlayBuffer*)malloc(sizeof(OverlayBuffer));
139 if (ovBuff == NULL) {
140 si.overlayLock.Release();
141 return NULL; // memory not available for OverlayBuffer struct
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));
154 if (prevOvBuff == NULL)
155 si.overlayBuffer = ovBuff;
156 else
157 prevOvBuff->nextBuffer = ovBuff;
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;
166 status_t
167 ReleaseOverlayBuffer(const overlay_buffer* buffer)
169 SharedInfo& si = *gInfo.sharedInfo;
171 TRACE("ReleaseOverlayBuffer() called\n");
173 if (buffer == NULL)
174 return B_BAD_VALUE;
176 // Find the buffer to be released.
178 OverlayBuffer* ovBuff = si.overlayBuffer;
179 OverlayBuffer* prevOvBuff = NULL;
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.
186 if (prevOvBuff == NULL)
187 si.overlayBuffer = ovBuff->nextBuffer;
188 else
189 prevOvBuff->nextBuffer = ovBuff->nextBuffer;
191 free(ovBuff);
192 TRACE("ReleaseOverlayBuffer() return OK\n");
193 return B_OK;
196 prevOvBuff = ovBuff;
197 ovBuff = ovBuff->nextBuffer;
200 return B_ERROR; // buffer to be released not found in chain of buffers
204 status_t
205 GetOverlayConstraints(const display_mode* mode, const overlay_buffer* buffer,
206 overlay_constraints* constraints)
208 if ((mode == NULL) || (buffer == NULL) || (constraints == NULL))
209 return B_ERROR;
211 // Position (values are in pixels)
212 constraints->view.h_alignment = 0;
213 constraints->view.v_alignment = 0;
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;
226 constraints->view.height_alignment = 0;
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;
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;
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;
249 return B_OK;
253 overlay_token
254 AllocateOverlay(void)
256 SharedInfo& si = *gInfo.sharedInfo;
258 TRACE("AllocateOverlay() called\n");
260 // There is only a single overlay channel; thus, check if it is already
261 // allocated.
263 if (atomic_or(&si.overlayAllocated, 1) != 0) {
264 TRACE("AllocateOverlay() overlay channel already in use\n");
265 return NULL;
267 TRACE("AllocateOverlay() Overlay allocated, overlayToken: %d\n",
268 si.overlayToken);
269 return (overlay_token)++si.overlayToken;
273 status_t
274 ReleaseOverlay(overlay_token overlayToken)
276 SharedInfo& si = *gInfo.sharedInfo;
278 TRACE("ReleaseOverlay() called\n");
280 if (overlayToken != (overlay_token)si.overlayToken)
281 return B_BAD_VALUE;
283 TDFX_StopOverlay();
285 atomic_and(&si.overlayAllocated, 0); // mark overlay as unallocated
287 TRACE("ReleaseOverlay() return OK\n");
288 return B_OK;
292 status_t
293 ConfigureOverlay (overlay_token overlayToken, const overlay_buffer* buffer,
294 const overlay_window* window, const overlay_view* view)
296 SharedInfo& si = *gInfo.sharedInfo;
298 if (overlayToken != (overlay_token)si.overlayToken)
299 return B_BAD_VALUE;
301 if (buffer == NULL)
302 return B_BAD_VALUE;
304 if (window == NULL || view == NULL) {
305 TDFX_StopOverlay();
306 TRACE("ConfigureOverlay() hide only\n");
307 return B_OK;
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;
316 return B_OK;