/ CoreGraphics / CGLPixelSurface.m
CGLPixelSurface.m
1 #define GL_GLEXT_PROTOTYPES 1 2 3 #import <CoreGraphics/CGLPixelSurface.h> 4 #import <CoreGraphics/CGWindow.h> 5 #import <Onyx2D/O2Image.h> 6 7 // this should be fixed upstream 8 #ifndef DARLING 9 #import <AppKit/O2Surface_DIBSection.h> 10 #else 11 #import <Onyx2D/O2Surface.h> 12 #endif 13 14 @implementation CGLPixelSurface 15 16 - initWithSize: (O2Size) size { 17 _width = size.width; 18 _height = size.height; 19 _validBuffers = NO; 20 _numberOfBuffers = 0; 21 _bufferObjects = NULL; 22 _readPixels = NULL; 23 _staticPixels = NULL; 24 return self; 25 } 26 27 - (void) dealloc { 28 [_surface release]; 29 [super dealloc]; 30 } 31 32 - (void) setFrameSize: (O2Size) value { 33 _width = value.width; 34 _height = value.height; 35 36 _validBuffers = NO; 37 } 38 39 - (void) setOpaque: (BOOL) value { 40 _isOpaque = value; 41 } 42 43 - (void) validateBuffersIfNeeded { 44 int i; 45 46 if (_validBuffers) 47 return; 48 49 // 0's are silently ignored per spec. 50 if (_numberOfBuffers > 0 && 51 _bufferObjects != NULL) // nVidia driver will crash if bufferObjects is 52 // NULL, does not conform to spec. 53 glDeleteBuffers(_numberOfBuffers, _bufferObjects); 54 55 if (_bufferObjects != NULL) 56 free(_bufferObjects); 57 58 if (_readPixels != NULL) 59 free(_readPixels); 60 61 if (_staticPixels != NULL) 62 free(_staticPixels); 63 64 [_surface release]; 65 66 _validBuffers = YES; 67 _numberOfBuffers = 1; 68 _rowsPerBuffer = (_height + (_numberOfBuffers - 1)) / _numberOfBuffers; 69 _bufferObjects = malloc(_numberOfBuffers * sizeof(GLuint)); 70 _readPixels = malloc(_numberOfBuffers * sizeof(void *)); 71 _staticPixels = malloc(_numberOfBuffers * sizeof(void *)); 72 #ifndef DARLING 73 _surface = [[O2Surface_DIBSection alloc] initWithWidth: _width 74 height: -_height 75 compatibleWithDeviceContext: nil]; 76 #else 77 O2ColorSpaceRef colorSpace = O2ColorSpaceCreateDeviceRGB(); 78 _surface = 79 [[O2Surface alloc] initWithBytes: NULL 80 width: _width 81 height: -_height 82 bitsPerComponent: 8 83 bytesPerRow: 0 84 colorSpace: colorSpace 85 bitmapInfo: kO2ImageAlphaPremultipliedFirst | 86 kO2BitmapByteOrder32Little]; 87 O2ColorSpaceRelease(colorSpace); 88 #endif 89 90 for (i = 0; i < _numberOfBuffers; i++) { 91 _bufferObjects[i] = 0; 92 _readPixels[i] = NULL; 93 _staticPixels[i] = NULL; 94 } 95 96 // CGLGenBuffers(_numberOfBuffers,_bufferObjects); 97 98 int row = 0, bytesPerRow = _width * 4; 99 100 for (i = 0; i < _numberOfBuffers; i++) { 101 _staticPixels[i] = 102 ((uint8_t *) [_surface pixelBytes]) + row * bytesPerRow; 103 104 if (_bufferObjects[i] == 0) { 105 _readPixels[i] = _staticPixels[i]; 106 } else { 107 _readPixels[i] = NULL; 108 glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, _bufferObjects[i]); 109 glBufferData(GL_PIXEL_PACK_BUFFER_ARB, _width * _rowsPerBuffer * 4, 110 NULL, GL_STREAM_READ); 111 glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0); 112 } 113 114 row += _rowsPerBuffer; 115 } 116 } 117 118 //#define RGBA_NOT_BGRA 1 119 120 #ifdef RGBA_NOT_BGRA 121 #define PIXEL_FORMAT GL_RGBA 122 #else 123 #define PIXEL_FORMAT GL_BGRA 124 #endif 125 126 static inline uint32_t setAlpha255(uint32_t value) { 127 #ifdef RGBA_NOT_BGRA 128 unsigned int a = 0xFF; 129 unsigned int b = (value >> 16) & 0xFF; 130 unsigned int g = (value >> 8) & 0xFF; 131 unsigned int r = (value >> 0) & 0xFF; 132 133 value = a << 24; 134 value |= r << 16; 135 value |= g << 8; 136 value |= b; 137 138 return value; 139 #else 140 return value |= 0xFF000000; 141 #endif 142 } 143 144 static inline uint32_t premultiplyPixel(uint32_t value) { 145 #ifdef RGBA_NOT_BGRA 146 unsigned int a = (value >> 24) & 0xFF; 147 unsigned int b = (value >> 16) & 0xFF; 148 unsigned int g = (value >> 8) & 0xFF; 149 unsigned int r = (value >> 0) & 0xFF; 150 #else 151 unsigned int a = (value >> 24) & 0xFF; 152 unsigned int r = (value >> 16) & 0xFF; 153 unsigned int g = (value >> 8) & 0xFF; 154 unsigned int b = (value >> 0) & 0xFF; 155 #endif 156 157 value &= 0xFF000000; 158 value |= O2Image_8u_mul_8u_div_255(r, a) << 16; 159 value |= O2Image_8u_mul_8u_div_255(g, a) << 8; 160 value |= O2Image_8u_mul_8u_div_255(b, a); 161 162 return value; 163 } 164 165 - (O2Surface *) validSurface { 166 [self validateBuffersIfNeeded]; 167 return _surface; 168 } 169 170 - (void) readBuffer { 171 172 [self validateBuffersIfNeeded]; 173 174 int bytesPerRow = _width * 4; 175 int i, row = 0; 176 177 if (glGetError() != GL_NO_ERROR) 178 return; 179 #if 0 180 glPixelStorei(GL_PACK_ALIGNMENT, 4); 181 glPixelStorei(GL_PACK_ROW_LENGTH, 0); 182 glPixelStorei(GL_PACK_SKIP_ROWS, 0); 183 glPixelStorei(GL_PACK_SKIP_PIXELS, 0); 184 #endif 185 186 // Technically shouldn't need unbind, but to be safe 187 BOOL unbind = NO; 188 189 for (i = 0; i < _numberOfBuffers; i++) { 190 int rowCount = MIN(_height - row, _rowsPerBuffer); 191 192 if (_bufferObjects[i] == 0) 193 glReadPixels(0, row, _width, rowCount, PIXEL_FORMAT, 194 GL_UNSIGNED_BYTE, _readPixels[i]); 195 else { 196 glBindBuffer(GL_PIXEL_PACK_BUFFER, _bufferObjects[i]); 197 unbind = YES; 198 199 glReadPixels(0, row, _width, rowCount, PIXEL_FORMAT, 200 GL_UNSIGNED_BYTE, 0); 201 } 202 203 GLenum error = glGetError(); 204 if (error != GL_NO_ERROR) { 205 NSLog(@"glReadPixels error=%d", error); 206 } 207 row += rowCount; 208 } 209 210 if (unbind) 211 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 212 213 row = 0; 214 unbind = NO; 215 216 for (i = 0; i < _numberOfBuffers; i++) { 217 int r, rowCount = MIN(_height - row, _rowsPerBuffer); 218 unsigned char *inputRow; 219 unsigned char *outputRow = _staticPixels[i]; 220 221 if (_bufferObjects[i] == 0) 222 inputRow = _readPixels[i]; 223 else { 224 unbind = YES; 225 glBindBuffer(GL_PIXEL_PACK_BUFFER, _bufferObjects[i]); 226 inputRow = 227 (GLubyte *) glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); 228 } 229 230 if (_isOpaque) { 231 // Opaque contexts ignore alpha so we set it to 0xFF to get proper 232 // results when blending E.g. application clears context with color 233 // and zero alpha, this will display as the color on OS X reading 234 // back will give us 0 alpha, premultiplying will give us black, 235 // which would be wrong. 236 237 for (r = 0; r < rowCount; 238 r++, inputRow += bytesPerRow, outputRow += bytesPerRow) { 239 int c; 240 241 for (c = 0; c < bytesPerRow; c += 4) { 242 uint32_t pixel = *((uint32_t *) (inputRow + c)); 243 244 pixel = setAlpha255(pixel); 245 246 *((uint32_t *) (outputRow + c)) = pixel; 247 } 248 } 249 } else { 250 for (r = 0; r < rowCount; 251 r++, inputRow += bytesPerRow, outputRow += bytesPerRow) { 252 int c; 253 254 for (c = 0; c < bytesPerRow; c += 4) { 255 uint32_t pixel = *((uint32_t *) (inputRow + c)); 256 257 pixel = premultiplyPixel(pixel); 258 259 *((uint32_t *) (outputRow + c)) = pixel; 260 } 261 } 262 } 263 264 if (_bufferObjects[i] != 0) { 265 glUnmapBuffer(GL_PIXEL_PACK_BUFFER); 266 } 267 268 row += rowCount; 269 } 270 271 if (unbind) 272 glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 273 274 #if 0 275 if(_usePixelBuffer){ 276 glBindBuffer(GL_PIXEL_PACK_BUFFER,0); 277 if(inputBytes!=NULL){ 278 CGLUnmapBuffer(GL_PIXEL_PACK_BUFFER); 279 } 280 } 281 #endif 282 } 283 284 - (NSString *) description { 285 return [NSString stringWithFormat: @"<%@ %p:size={ %d %d } surface=%@", 286 [self class], self, _width, _height, 287 _surface]; 288 } 289 290 @end