rsAllocation.cpp revision 707aaf341a4b068e6ccadf923af85acdd85fd775
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "rsContext.h" 18 19#include <GLES/gl.h> 20#include <GLES/glext.h> 21 22using namespace android; 23using namespace android::renderscript; 24 25Allocation::Allocation(const Type *type) 26{ 27 mPtr = NULL; 28 29 mCpuWrite = false; 30 mCpuRead = false; 31 mGpuWrite = false; 32 mGpuRead = false; 33 34 mReadWriteRatio = 0; 35 mUpdateSize = 0; 36 37 mIsTexture = false; 38 mTextureID = 0; 39 40 mIsVertexBuffer = false; 41 mBufferID = 0; 42 43 mType.set(type); 44 rsAssert(type); 45 mPtr = malloc(mType->getSizeBytes()); 46 if (!mPtr) { 47 LOGE("Allocation::Allocation, alloc failure"); 48 } 49} 50 51Allocation::~Allocation() 52{ 53} 54 55void Allocation::setCpuWritable(bool) 56{ 57} 58 59void Allocation::setGpuWritable(bool) 60{ 61} 62 63void Allocation::setCpuReadable(bool) 64{ 65} 66 67void Allocation::setGpuReadable(bool) 68{ 69} 70 71bool Allocation::fixAllocation() 72{ 73 return false; 74} 75 76void Allocation::uploadToTexture(uint32_t lodOffset) 77{ 78 //rsAssert(!mTextureId); 79 rsAssert(lodOffset < mType->getLODCount()); 80 81 GLenum type = mType->getElement()->getGLType(); 82 GLenum format = mType->getElement()->getGLFormat(); 83 84 if (!type || !format) { 85 return; 86 } 87 88 if (!mTextureID) { 89 glGenTextures(1, &mTextureID); 90 } 91 glBindTexture(GL_TEXTURE_2D, mTextureID); 92 93 Adapter2D adapt(this); 94 for(uint32_t lod = 0; (lod + lodOffset) < mType->getLODCount(); lod++) { 95 adapt.setLOD(lod+lodOffset); 96 97 uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0)); 98 glTexImage2D(GL_TEXTURE_2D, lod, format, 99 adapt.getDimX(), adapt.getDimY(), 100 0, format, type, ptr); 101 } 102} 103 104void Allocation::uploadToBufferObject() 105{ 106 rsAssert(!mType->getDimY()); 107 rsAssert(!mType->getDimZ()); 108 109 if (!mBufferID) { 110 glGenBuffers(1, &mBufferID); 111 } 112 glBindBuffer(GL_ARRAY_BUFFER, mBufferID); 113 glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW); 114 glBindBuffer(GL_ARRAY_BUFFER, 0); 115} 116 117 118void Allocation::data(const void *data) 119{ 120 memcpy(mPtr, data, mType->getSizeBytes()); 121} 122 123void Allocation::read(void *data) 124{ 125 memcpy(data, mPtr, mType->getSizeBytes()); 126} 127 128void Allocation::subData(uint32_t xoff, uint32_t count, const void *data) 129{ 130 uint32_t eSize = mType->getElementSizeBytes(); 131 uint8_t * ptr = static_cast<uint8_t *>(mPtr); 132 ptr += eSize * xoff; 133 memcpy(ptr, data, count * eSize); 134} 135 136void Allocation::subData(uint32_t xoff, uint32_t yoff, 137 uint32_t w, uint32_t h, const void *data) 138{ 139 uint32_t eSize = mType->getElementSizeBytes(); 140 uint32_t lineSize = eSize * w; 141 uint32_t destW = mType->getDimX(); 142 143 const uint8_t *src = static_cast<const uint8_t *>(data); 144 uint8_t *dst = static_cast<uint8_t *>(mPtr); 145 dst += eSize * (xoff + yoff * destW); 146 for (uint32_t line=yoff; line < (yoff+h); line++) { 147 uint8_t * ptr = static_cast<uint8_t *>(mPtr); 148 memcpy(dst, src, lineSize); 149 src += lineSize; 150 dst += destW * eSize; 151 } 152} 153 154void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff, 155 uint32_t w, uint32_t h, uint32_t d, const void *data) 156{ 157} 158 159 160 161///////////////// 162// 163 164 165namespace android { 166namespace renderscript { 167 168RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype) 169{ 170 const Type * type = static_cast<const Type *>(vtype); 171 172 Allocation * alloc = new Allocation(type); 173 alloc->incRef(); 174 return alloc; 175} 176 177RsAllocation rsi_AllocationCreatePredefSized(Context *rsc, RsElementPredefined t, size_t count) 178{ 179 RsElement e = rsi_ElementGetPredefined(rsc, t); 180 return rsi_AllocationCreateSized(rsc, e, count); 181} 182 183RsAllocation rsi_AllocationCreateSized(Context *rsc, RsElement e, size_t count) 184{ 185 Type * type = new Type(); 186 type->setDimX(count); 187 type->setElement(static_cast<Element *>(e)); 188 type->compute(); 189 return rsi_AllocationCreateTyped(rsc, type); 190} 191 192void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, uint32_t baseMipLevel) 193{ 194 Allocation *alloc = static_cast<Allocation *>(va); 195 alloc->uploadToTexture(baseMipLevel); 196} 197 198void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va) 199{ 200 Allocation *alloc = static_cast<Allocation *>(va); 201 alloc->uploadToBufferObject(); 202} 203 204static void mip565(const Adapter2D &out, const Adapter2D &in) 205{ 206 uint32_t w = out.getDimX(); 207 uint32_t h = out.getDimY(); 208 209 for (uint32_t y=0; y < h; y++) { 210 uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y)); 211 const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2)); 212 const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1)); 213 214 for (uint32_t x=0; x < w; x++) { 215 *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]); 216 oPtr ++; 217 i1 += 2; 218 i2 += 2; 219 } 220 } 221} 222 223static void mip8888(const Adapter2D &out, const Adapter2D &in) 224{ 225 uint32_t w = out.getDimX(); 226 uint32_t h = out.getDimY(); 227 228 for (uint32_t y=0; y < h; y++) { 229 uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y)); 230 const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2)); 231 const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1)); 232 233 for (uint32_t x=0; x < w; x++) { 234 *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]); 235 oPtr ++; 236 i1 += 2; 237 i2 += 2; 238 } 239 } 240} 241 242static void mip(const Adapter2D &out, const Adapter2D &in) 243{ 244 switch(out.getBaseType()->getElement()->getSizeBits()) { 245 case 32: 246 mip8888(out, in); 247 break; 248 case 16: 249 mip565(out, in); 250 break; 251 252 } 253 254} 255 256typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count); 257 258static void elementConverter_cpy_16(void *dst, const void *src, uint32_t count) 259{ 260 memcpy(dst, src, count * 2); 261} 262static void elementConverter_cpy_8(void *dst, const void *src, uint32_t count) 263{ 264 memcpy(dst, src, count); 265} 266static void elementConverter_cpy_32(void *dst, const void *src, uint32_t count) 267{ 268 memcpy(dst, src, count * 4); 269} 270 271 272static void elementConverter_888_to_565(void *dst, const void *src, uint32_t count) 273{ 274 uint16_t *d = static_cast<uint16_t *>(dst); 275 const uint8_t *s = static_cast<const uint8_t *>(src); 276 277 while(count--) { 278 *d = rs888to565(s[0], s[1], s[2]); 279 d++; 280 s+= 3; 281 } 282} 283 284static void elementConverter_8888_to_565(void *dst, const void *src, uint32_t count) 285{ 286 uint16_t *d = static_cast<uint16_t *>(dst); 287 const uint8_t *s = static_cast<const uint8_t *>(src); 288 289 while(count--) { 290 *d = rs888to565(s[0], s[1], s[2]); 291 d++; 292 s+= 4; 293 } 294} 295 296static ElementConverter_t pickConverter(RsElementPredefined dstFmt, RsElementPredefined srcFmt) 297{ 298 if ((dstFmt == RS_ELEMENT_RGB_565) && 299 (srcFmt == RS_ELEMENT_RGB_565)) { 300 return elementConverter_cpy_16; 301 } 302 303 if ((dstFmt == RS_ELEMENT_RGB_565) && 304 (srcFmt == RS_ELEMENT_RGB_888)) { 305 return elementConverter_888_to_565; 306 } 307 308 if ((dstFmt == RS_ELEMENT_RGB_565) && 309 (srcFmt == RS_ELEMENT_RGBA_8888)) { 310 return elementConverter_8888_to_565; 311 } 312 313 if ((dstFmt == RS_ELEMENT_RGBA_8888) && 314 (srcFmt == RS_ELEMENT_RGBA_8888)) { 315 return elementConverter_cpy_32; 316 } 317 318 LOGE("pickConverter, unsuported combo, src %i, dst %i", srcFmt, dstFmt); 319 return 0; 320} 321 322 323RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data) 324{ 325 rsAssert(!(w & (w-1))); 326 rsAssert(!(h & (h-1))); 327 328 //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips); 329 rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, dstFmt)); 330 rsi_TypeAdd(rsc, RS_DIMENSION_X, w); 331 rsi_TypeAdd(rsc, RS_DIMENSION_Y, h); 332 if (genMips) { 333 rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1); 334 } 335 RsType type = rsi_TypeCreate(rsc); 336 337 RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type); 338 Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc); 339 if (texAlloc == NULL) { 340 LOGE("Memory allocation failure"); 341 return NULL; 342 } 343 texAlloc->incRef(); 344 345 ElementConverter_t cvt = pickConverter(dstFmt, srcFmt); 346 cvt(texAlloc->getPtr(), data, w * h); 347 348 if (genMips) { 349 Adapter2D adapt(texAlloc); 350 Adapter2D adapt2(texAlloc); 351 for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) { 352 adapt.setLOD(lod); 353 adapt2.setLOD(lod + 1); 354 mip(adapt2, adapt); 355 } 356 } 357 358 return texAlloc; 359} 360 361static uint32_t fmtToBits(RsElementPredefined fmt) 362{ 363 return 16; 364} 365 366RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElementPredefined dstFmt, RsElementPredefined srcFmt, bool genMips, const void *data) 367{ 368 uint32_t w2 = rsHigherPow2(w); 369 uint32_t h2 = rsHigherPow2(h); 370 371 if ((w2 == w) && (h2 == h)) { 372 return rsi_AllocationCreateFromBitmap(rsc, w, h, dstFmt, srcFmt, genMips, data); 373 } 374 375 uint32_t bpp = fmtToBits(srcFmt) >> 3; 376 size_t size = w2 * h2 * bpp; 377 uint8_t *tmp = static_cast<uint8_t *>(malloc(size)); 378 memset(tmp, 0, size); 379 380 const uint8_t * src = static_cast<const uint8_t *>(data); 381 for (uint32_t y = 0; y < h; y++) { 382 uint8_t * ydst = &tmp[(y + ((h2 - h) >> 1)) * w2 * bpp]; 383 memcpy(&ydst[(w2 - w) >> 1], src, w * bpp); 384 src += w * bpp; 385 } 386 387 RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, dstFmt, srcFmt, genMips, tmp); 388 free(tmp); 389 return ret; 390 391 392 393 394} 395 396 397RsAllocation rsi_AllocationCreateFromFile(Context *rsc, const char *file, bool genMips) 398{ 399 bool use32bpp = false; 400 401 typedef struct _Win3xBitmapHeader 402 { 403 uint16_t type; 404 uint32_t totalSize; 405 uint32_t reserved; 406 uint32_t offset; 407 int32_t hdrSize; /* Size of this header in bytes */ 408 int32_t width; /* Image width in pixels */ 409 int32_t height; /* Image height in pixels */ 410 int16_t planes; /* Number of color planes */ 411 int16_t bpp; /* Number of bits per pixel */ 412 /* Fields added for Windows 3.x follow this line */ 413 int32_t compression; /* Compression methods used */ 414 int32_t sizeOfBitmap; /* Size of bitmap in bytes */ 415 int32_t horzResolution; /* Horizontal resolution in pixels per meter */ 416 int32_t vertResolution; /* Vertical resolution in pixels per meter */ 417 int32_t colorsUsed; /* Number of colors in the image */ 418 int32_t colorsImportant; /* Minimum number of important colors */ 419 } __attribute__((__packed__)) WIN3XBITMAPHEADER; 420 421 _Win3xBitmapHeader hdr; 422 423 FILE *f = fopen(file, "rb"); 424 if (f == NULL) { 425 LOGE("rsAllocationCreateFromBitmap failed to open file %s", file); 426 return NULL; 427 } 428 memset(&hdr, 0, sizeof(hdr)); 429 fread(&hdr, sizeof(hdr), 1, f); 430 431 if (hdr.bpp != 24) { 432 LOGE("Unsuported BMP type"); 433 fclose(f); 434 return NULL; 435 } 436 437 int32_t texWidth = rsHigherPow2(hdr.width); 438 int32_t texHeight = rsHigherPow2(hdr.height); 439 440 if (use32bpp) { 441 rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGBA_8888)); 442 } else { 443 rsi_TypeBegin(rsc, rsi_ElementGetPredefined(rsc, RS_ELEMENT_RGB_565)); 444 } 445 rsi_TypeAdd(rsc, RS_DIMENSION_X, texWidth); 446 rsi_TypeAdd(rsc, RS_DIMENSION_Y, texHeight); 447 if (genMips) { 448 rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1); 449 } 450 RsType type = rsi_TypeCreate(rsc); 451 452 RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type); 453 Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc); 454 texAlloc->incRef(); 455 if (texAlloc == NULL) { 456 LOGE("Memory allocation failure"); 457 fclose(f); 458 return NULL; 459 } 460 461 // offset to letterbox if height is not pow2 462 Adapter2D adapt(texAlloc); 463 uint8_t * fileInBuf = new uint8_t[texWidth * 3]; 464 uint32_t yOffset = (hdr.width - hdr.height) / 2; 465 466 if (use32bpp) { 467 uint8_t *tmp = static_cast<uint8_t *>(adapt.getElement(0, yOffset)); 468 for (int y=0; y < hdr.height; y++) { 469 fseek(f, hdr.offset + (y*hdr.width*3), SEEK_SET); 470 fread(fileInBuf, 1, hdr.width * 3, f); 471 for(int x=0; x < hdr.width; x++) { 472 tmp[0] = fileInBuf[x*3 + 2]; 473 tmp[1] = fileInBuf[x*3 + 1]; 474 tmp[2] = fileInBuf[x*3]; 475 tmp[3] = 0xff; 476 tmp += 4; 477 } 478 } 479 } else { 480 uint16_t *tmp = static_cast<uint16_t *>(adapt.getElement(0, yOffset)); 481 for (int y=0; y < hdr.height; y++) { 482 fseek(f, hdr.offset + (y*hdr.width*3), SEEK_SET); 483 fread(fileInBuf, 1, hdr.width * 3, f); 484 for(int x=0; x < hdr.width; x++) { 485 *tmp = rs888to565(fileInBuf[x*3 + 2], fileInBuf[x*3 + 1], fileInBuf[x*3]); 486 tmp++; 487 } 488 } 489 } 490 491 fclose(f); 492 delete [] fileInBuf; 493 494 if (genMips) { 495 Adapter2D adapt2(texAlloc); 496 for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) { 497 adapt.setLOD(lod); 498 adapt2.setLOD(lod + 1); 499 mip(adapt2, adapt); 500 } 501 } 502 503 return texAlloc; 504} 505 506void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data) 507{ 508 Allocation *a = static_cast<Allocation *>(va); 509 a->data(data); 510 rsc->allocationCheck(a); 511} 512 513void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data) 514{ 515 Allocation *a = static_cast<Allocation *>(va); 516 a->subData(xoff, count, data); 517 rsc->allocationCheck(a); 518} 519 520void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data) 521{ 522 Allocation *a = static_cast<Allocation *>(va); 523 a->subData(xoff, yoff, w, h, data); 524 rsc->allocationCheck(a); 525} 526 527void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data) 528{ 529 Allocation *a = static_cast<Allocation *>(va); 530 a->read(data); 531} 532 533 534} 535} 536