rsdAllocation.cpp revision 179e9a457095fea4c9e6d366c269754b882d05dd
1/* 2 * Copyright (C) 2011 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 18#include "rsdCore.h" 19#include "rsdBcc.h" 20#include "rsdRuntime.h" 21#include "rsdAllocation.h" 22#include "rsdFrameBufferObj.h" 23 24#include "rsAllocation.h" 25 26#include <GLES/gl.h> 27#include <GLES2/gl2.h> 28#include <GLES/glext.h> 29 30using namespace android; 31using namespace android::renderscript; 32 33 34 35const static GLenum gFaceOrder[] = { 36 GL_TEXTURE_CUBE_MAP_POSITIVE_X, 37 GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 38 GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 39 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 40 GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 41 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 42}; 43 44 45GLenum rsdTypeToGLType(RsDataType t) { 46 switch (t) { 47 case RS_TYPE_UNSIGNED_5_6_5: return GL_UNSIGNED_SHORT_5_6_5; 48 case RS_TYPE_UNSIGNED_5_5_5_1: return GL_UNSIGNED_SHORT_5_5_5_1; 49 case RS_TYPE_UNSIGNED_4_4_4_4: return GL_UNSIGNED_SHORT_4_4_4_4; 50 51 //case RS_TYPE_FLOAT_16: return GL_HALF_FLOAT; 52 case RS_TYPE_FLOAT_32: return GL_FLOAT; 53 case RS_TYPE_UNSIGNED_8: return GL_UNSIGNED_BYTE; 54 case RS_TYPE_UNSIGNED_16: return GL_UNSIGNED_SHORT; 55 case RS_TYPE_SIGNED_8: return GL_BYTE; 56 case RS_TYPE_SIGNED_16: return GL_SHORT; 57 default: break; 58 } 59 return 0; 60} 61 62GLenum rsdKindToGLFormat(RsDataKind k) { 63 switch (k) { 64 case RS_KIND_PIXEL_L: return GL_LUMINANCE; 65 case RS_KIND_PIXEL_A: return GL_ALPHA; 66 case RS_KIND_PIXEL_LA: return GL_LUMINANCE_ALPHA; 67 case RS_KIND_PIXEL_RGB: return GL_RGB; 68 case RS_KIND_PIXEL_RGBA: return GL_RGBA; 69 case RS_KIND_PIXEL_DEPTH: return GL_DEPTH_COMPONENT16; 70 default: break; 71 } 72 return 0; 73} 74 75 76static void Update2DTexture(const Context *rsc, const Allocation *alloc, const void *ptr, 77 uint32_t xoff, uint32_t yoff, uint32_t lod, 78 RsAllocationCubemapFace face, uint32_t w, uint32_t h) { 79 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 80 81 rsAssert(drv->textureID); 82 RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID); 83 RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1); 84 GLenum t = GL_TEXTURE_2D; 85 if (alloc->mHal.state.hasFaces) { 86 t = gFaceOrder[face]; 87 } 88 RSD_CALL_GL(glTexSubImage2D, t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr); 89} 90 91 92static void Upload2DTexture(const Context *rsc, const Allocation *alloc, bool isFirstUpload) { 93 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 94 95 RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID); 96 RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1); 97 98 uint32_t faceCount = 1; 99 if (alloc->mHal.state.hasFaces) { 100 faceCount = 6; 101 } 102 103 rsdGLCheckError(rsc, "Upload2DTexture 1 "); 104 for (uint32_t face = 0; face < faceCount; face ++) { 105 for (uint32_t lod = 0; lod < alloc->mHal.state.type->getLODCount(); lod++) { 106 const uint8_t *p = (const uint8_t *)drv->mallocPtr; 107 p += alloc->mHal.state.type->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0); 108 109 GLenum t = GL_TEXTURE_2D; 110 if (alloc->mHal.state.hasFaces) { 111 t = gFaceOrder[face]; 112 } 113 114 if (isFirstUpload) { 115 RSD_CALL_GL(glTexImage2D, t, lod, drv->glFormat, 116 alloc->mHal.state.type->getLODDimX(lod), 117 alloc->mHal.state.type->getLODDimY(lod), 118 0, drv->glFormat, drv->glType, p); 119 } else { 120 RSD_CALL_GL(glTexSubImage2D, t, lod, 0, 0, 121 alloc->mHal.state.type->getLODDimX(lod), 122 alloc->mHal.state.type->getLODDimY(lod), 123 drv->glFormat, drv->glType, p); 124 } 125 } 126 } 127 128 if (alloc->mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) { 129 RSD_CALL_GL(glGenerateMipmap, drv->glTarget); 130 } 131 rsdGLCheckError(rsc, "Upload2DTexture"); 132} 133 134static void UploadToTexture(const Context *rsc, const Allocation *alloc) { 135 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 136 137 if (!drv->glType || !drv->glFormat) { 138 return; 139 } 140 141 if (!alloc->getPtr()) { 142 return; 143 } 144 145 bool isFirstUpload = false; 146 147 if (!drv->textureID) { 148 RSD_CALL_GL(glGenTextures, 1, &drv->textureID); 149 isFirstUpload = true; 150 } 151 152 Upload2DTexture(rsc, alloc, isFirstUpload); 153 154 if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) { 155 if (drv->mallocPtr) { 156 free(drv->mallocPtr); 157 drv->mallocPtr = NULL; 158 } 159 } 160 rsdGLCheckError(rsc, "UploadToTexture"); 161} 162 163static void AllocateRenderTarget(const Context *rsc, const Allocation *alloc) { 164 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 165 166 if (!drv->glFormat) { 167 return; 168 } 169 170 if (!drv->renderTargetID) { 171 RSD_CALL_GL(glGenRenderbuffers, 1, &drv->renderTargetID); 172 173 if (!drv->renderTargetID) { 174 // This should generally not happen 175 LOGE("allocateRenderTarget failed to gen mRenderTargetID"); 176 rsc->dumpDebug(); 177 return; 178 } 179 RSD_CALL_GL(glBindRenderbuffer, GL_RENDERBUFFER, drv->renderTargetID); 180 RSD_CALL_GL(glRenderbufferStorage, GL_RENDERBUFFER, drv->glFormat, 181 alloc->mHal.state.dimensionX, alloc->mHal.state.dimensionY); 182 } 183 rsdGLCheckError(rsc, "AllocateRenderTarget"); 184} 185 186static void UploadToBufferObject(const Context *rsc, const Allocation *alloc) { 187 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 188 189 rsAssert(!alloc->mHal.state.type->getDimY()); 190 rsAssert(!alloc->mHal.state.type->getDimZ()); 191 192 //alloc->mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; 193 194 if (!drv->bufferID) { 195 RSD_CALL_GL(glGenBuffers, 1, &drv->bufferID); 196 } 197 if (!drv->bufferID) { 198 LOGE("Upload to buffer object failed"); 199 drv->uploadDeferred = true; 200 return; 201 } 202 RSD_CALL_GL(glBindBuffer, drv->glTarget, drv->bufferID); 203 RSD_CALL_GL(glBufferData, drv->glTarget, alloc->mHal.state.type->getSizeBytes(), 204 drv->mallocPtr, GL_DYNAMIC_DRAW); 205 RSD_CALL_GL(glBindBuffer, drv->glTarget, 0); 206 rsdGLCheckError(rsc, "UploadToBufferObject"); 207} 208 209bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) { 210 DrvAllocation *drv = (DrvAllocation *)calloc(1, sizeof(DrvAllocation)); 211 if (!drv) { 212 return false; 213 } 214 215 void * ptr = alloc->mHal.state.usrPtr; 216 if (!ptr) { 217 ptr = malloc(alloc->mHal.state.type->getSizeBytes()); 218 if (!ptr) { 219 free(drv); 220 return false; 221 } 222 } 223 224 drv->glTarget = GL_NONE; 225 if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) { 226 if (alloc->mHal.state.hasFaces) { 227 drv->glTarget = GL_TEXTURE_CUBE_MAP; 228 } else { 229 drv->glTarget = GL_TEXTURE_2D; 230 } 231 } else { 232 if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) { 233 drv->glTarget = GL_ARRAY_BUFFER; 234 } 235 } 236 237 drv->glType = rsdTypeToGLType(alloc->mHal.state.type->getElement()->getComponent().getType()); 238 drv->glFormat = rsdKindToGLFormat(alloc->mHal.state.type->getElement()->getComponent().getKind()); 239 240 241 alloc->mHal.drvState.mallocPtr = ptr; 242 drv->mallocPtr = (uint8_t *)ptr; 243 alloc->mHal.drv = drv; 244 if (forceZero) { 245 memset(ptr, 0, alloc->mHal.state.type->getSizeBytes()); 246 } 247 248 if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) { 249 drv->uploadDeferred = true; 250 } 251 252 drv->readBackFBO = NULL; 253 254 return true; 255} 256 257void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) { 258 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 259 260 if (drv->bufferID) { 261 // Causes a SW crash.... 262 //ALOGV(" mBufferID %i", mBufferID); 263 //glDeleteBuffers(1, &mBufferID); 264 //mBufferID = 0; 265 } 266 if (drv->textureID) { 267 RSD_CALL_GL(glDeleteTextures, 1, &drv->textureID); 268 drv->textureID = 0; 269 } 270 if (drv->renderTargetID) { 271 RSD_CALL_GL(glDeleteRenderbuffers, 1, &drv->renderTargetID); 272 drv->renderTargetID = 0; 273 } 274 275 if (drv->mallocPtr && !alloc->mHal.state.usrPtr) { 276 free(drv->mallocPtr); 277 drv->mallocPtr = NULL; 278 } 279 if (drv->readBackFBO != NULL) { 280 delete drv->readBackFBO; 281 drv->readBackFBO = NULL; 282 } 283 free(drv); 284 alloc->mHal.drv = NULL; 285} 286 287void rsdAllocationResize(const Context *rsc, const Allocation *alloc, 288 const Type *newType, bool zeroNew) { 289 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 290 291 drv->mallocPtr = (uint8_t *)realloc(drv->mallocPtr, newType->getSizeBytes()); 292 293 // fixme 294 ((Allocation *)alloc)->mHal.drvState.mallocPtr = drv->mallocPtr; 295 296 const uint32_t oldDimX = alloc->mHal.state.dimensionX; 297 const uint32_t dimX = newType->getDimX(); 298 299 if (dimX > oldDimX) { 300 const Element *e = alloc->mHal.state.type->getElement(); 301 uint32_t stride = e->getSizeBytes(); 302 memset(((uint8_t *)drv->mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX)); 303 } 304} 305 306static void rsdAllocationSyncFromFBO(const Context *rsc, const Allocation *alloc) { 307 if (!alloc->getIsScript()) { 308 return; // nothing to sync 309 } 310 311 RsdHal *dc = (RsdHal *)rsc->mHal.drv; 312 RsdFrameBufferObj *lastFbo = dc->gl.currentFrameBuffer; 313 314 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 315 if (!drv->textureID && !drv->renderTargetID) { 316 return; // nothing was rendered here yet, so nothing to sync 317 } 318 if (drv->readBackFBO == NULL) { 319 drv->readBackFBO = new RsdFrameBufferObj(); 320 drv->readBackFBO->setColorTarget(drv, 0); 321 drv->readBackFBO->setDimensions(alloc->getType()->getDimX(), 322 alloc->getType()->getDimY()); 323 } 324 325 // Bind the framebuffer object so we can read back from it 326 drv->readBackFBO->setActive(rsc); 327 328 // Do the readback 329 RSD_CALL_GL(glReadPixels, 0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(), 330 drv->glFormat, drv->glType, alloc->getPtr()); 331 332 // Revert framebuffer to its original 333 lastFbo->setActive(rsc); 334} 335 336 337void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc, 338 RsAllocationUsageType src) { 339 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 340 341 if (src == RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) { 342 if(!alloc->getIsRenderTarget()) { 343 rsc->setError(RS_ERROR_FATAL_DRIVER, 344 "Attempting to sync allocation from render target, " 345 "for non-render target allocation"); 346 } else if (alloc->getType()->getElement()->getKind() != RS_KIND_PIXEL_RGBA) { 347 rsc->setError(RS_ERROR_FATAL_DRIVER, "Cannot only sync from RGBA" 348 "render target"); 349 } else { 350 rsdAllocationSyncFromFBO(rsc, alloc); 351 } 352 return; 353 } 354 355 rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT); 356 357 if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) { 358 UploadToTexture(rsc, alloc); 359 } else { 360 if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) { 361 AllocateRenderTarget(rsc, alloc); 362 } 363 } 364 if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) { 365 UploadToBufferObject(rsc, alloc); 366 } 367 368 drv->uploadDeferred = false; 369} 370 371void rsdAllocationMarkDirty(const Context *rsc, const Allocation *alloc) { 372 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 373 drv->uploadDeferred = true; 374} 375 376void rsdAllocationData1D(const Context *rsc, const Allocation *alloc, 377 uint32_t xoff, uint32_t lod, uint32_t count, 378 const void *data, uint32_t sizeBytes) { 379 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 380 381 const uint32_t eSize = alloc->mHal.state.type->getElementSizeBytes(); 382 uint8_t * ptr = drv->mallocPtr; 383 ptr += eSize * xoff; 384 uint32_t size = count * eSize; 385 386 if (alloc->mHal.state.hasReferences) { 387 alloc->incRefs(data, count); 388 alloc->decRefs(ptr, count); 389 } 390 391 memcpy(ptr, data, size); 392 drv->uploadDeferred = true; 393} 394 395void rsdAllocationData2D(const Context *rsc, const Allocation *alloc, 396 uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, 397 uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { 398 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 399 400 uint32_t eSize = alloc->mHal.state.elementSizeBytes; 401 uint32_t lineSize = eSize * w; 402 uint32_t destW = alloc->mHal.state.dimensionX; 403 404 if (drv->mallocPtr) { 405 const uint8_t *src = static_cast<const uint8_t *>(data); 406 uint8_t *dst = drv->mallocPtr; 407 dst += alloc->mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff); 408 409 for (uint32_t line=yoff; line < (yoff+h); line++) { 410 if (alloc->mHal.state.hasReferences) { 411 alloc->incRefs(src, w); 412 alloc->decRefs(dst, w); 413 } 414 memcpy(dst, src, lineSize); 415 src += lineSize; 416 dst += destW * eSize; 417 } 418 drv->uploadDeferred = true; 419 } else { 420 Update2DTexture(rsc, alloc, data, xoff, yoff, lod, face, w, h); 421 } 422} 423 424void rsdAllocationData3D(const Context *rsc, const Allocation *alloc, 425 uint32_t xoff, uint32_t yoff, uint32_t zoff, 426 uint32_t lod, RsAllocationCubemapFace face, 427 uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) { 428 429} 430 431void rsdAllocationData1D_alloc(const android::renderscript::Context *rsc, 432 const android::renderscript::Allocation *dstAlloc, 433 uint32_t dstXoff, uint32_t dstLod, uint32_t count, 434 const android::renderscript::Allocation *srcAlloc, 435 uint32_t srcXoff, uint32_t srcLod) { 436} 437 438uint8_t *getOffsetPtr(const android::renderscript::Allocation *alloc, 439 uint32_t xoff, uint32_t yoff, uint32_t lod, 440 RsAllocationCubemapFace face) { 441 uint8_t *ptr = static_cast<uint8_t *>(alloc->getPtr()); 442 ptr += alloc->getType()->getLODOffset(lod, xoff, yoff); 443 444 if (face != 0) { 445 uint32_t totalSizeBytes = alloc->getType()->getSizeBytes(); 446 uint32_t faceOffset = totalSizeBytes / 6; 447 ptr += faceOffset * (uint32_t)face; 448 } 449 return ptr; 450} 451 452 453void rsdAllocationData2D_alloc_script(const android::renderscript::Context *rsc, 454 const android::renderscript::Allocation *dstAlloc, 455 uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod, 456 RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h, 457 const android::renderscript::Allocation *srcAlloc, 458 uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod, 459 RsAllocationCubemapFace srcFace) { 460 uint32_t elementSize = dstAlloc->getType()->getElementSizeBytes(); 461 for (uint32_t i = 0; i < h; i ++) { 462 uint8_t *dstPtr = getOffsetPtr(dstAlloc, dstXoff, dstYoff + i, dstLod, dstFace); 463 uint8_t *srcPtr = getOffsetPtr(srcAlloc, srcXoff, srcYoff + i, srcLod, srcFace); 464 memcpy(dstPtr, srcPtr, w * elementSize); 465 466 //LOGE("COPIED dstXoff(%u), dstYoff(%u), dstLod(%u), dstFace(%u), w(%u), h(%u), srcXoff(%u), srcYoff(%u), srcLod(%u), srcFace(%u)", 467 // dstXoff, dstYoff, dstLod, dstFace, w, h, srcXoff, srcYoff, srcLod, srcFace); 468 } 469} 470 471void rsdAllocationData2D_alloc(const android::renderscript::Context *rsc, 472 const android::renderscript::Allocation *dstAlloc, 473 uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod, 474 RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h, 475 const android::renderscript::Allocation *srcAlloc, 476 uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod, 477 RsAllocationCubemapFace srcFace) { 478 if (!dstAlloc->getIsScript() && !srcAlloc->getIsScript()) { 479 rsc->setError(RS_ERROR_FATAL_DRIVER, "Non-script allocation copies not " 480 "yet implemented."); 481 return; 482 } 483 rsdAllocationData2D_alloc_script(rsc, dstAlloc, dstXoff, dstYoff, 484 dstLod, dstFace, w, h, srcAlloc, 485 srcXoff, srcYoff, srcLod, srcFace); 486} 487 488void rsdAllocationData3D_alloc(const android::renderscript::Context *rsc, 489 const android::renderscript::Allocation *dstAlloc, 490 uint32_t dstXoff, uint32_t dstYoff, uint32_t dstZoff, 491 uint32_t dstLod, RsAllocationCubemapFace dstFace, 492 uint32_t w, uint32_t h, uint32_t d, 493 const android::renderscript::Allocation *srcAlloc, 494 uint32_t srcXoff, uint32_t srcYoff, uint32_t srcZoff, 495 uint32_t srcLod, RsAllocationCubemapFace srcFace) { 496} 497 498void rsdAllocationElementData1D(const Context *rsc, const Allocation *alloc, 499 uint32_t x, 500 const void *data, uint32_t cIdx, uint32_t sizeBytes) { 501 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 502 503 uint32_t eSize = alloc->mHal.state.elementSizeBytes; 504 uint8_t * ptr = drv->mallocPtr; 505 ptr += eSize * x; 506 507 const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx); 508 ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); 509 510 if (alloc->mHal.state.hasReferences) { 511 e->incRefs(data); 512 e->decRefs(ptr); 513 } 514 515 memcpy(ptr, data, sizeBytes); 516 drv->uploadDeferred = true; 517} 518 519void rsdAllocationElementData2D(const Context *rsc, const Allocation *alloc, 520 uint32_t x, uint32_t y, 521 const void *data, uint32_t cIdx, uint32_t sizeBytes) { 522 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 523 524 uint32_t eSize = alloc->mHal.state.elementSizeBytes; 525 uint8_t * ptr = drv->mallocPtr; 526 ptr += eSize * (x + y * alloc->mHal.state.dimensionX); 527 528 const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx); 529 ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); 530 531 if (alloc->mHal.state.hasReferences) { 532 e->incRefs(data); 533 e->decRefs(ptr); 534 } 535 536 memcpy(ptr, data, sizeBytes); 537 drv->uploadDeferred = true; 538} 539 540 541