rsdAllocation.cpp revision cf27eb46f97cff087ebfc5b81fe998eabe0569cf
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 (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) { 138 if (!drv->textureID) { 139 RSD_CALL_GL(glGenTextures, 1, &drv->textureID); 140 } 141 return; 142 } 143 144 if (!drv->glType || !drv->glFormat) { 145 return; 146 } 147 148 if (!alloc->getPtr()) { 149 return; 150 } 151 152 bool isFirstUpload = false; 153 154 if (!drv->textureID) { 155 RSD_CALL_GL(glGenTextures, 1, &drv->textureID); 156 isFirstUpload = true; 157 } 158 159 Upload2DTexture(rsc, alloc, isFirstUpload); 160 161 if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) { 162 if (drv->mallocPtr) { 163 free(drv->mallocPtr); 164 drv->mallocPtr = NULL; 165 } 166 } 167 rsdGLCheckError(rsc, "UploadToTexture"); 168} 169 170static void AllocateRenderTarget(const Context *rsc, const Allocation *alloc) { 171 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 172 173 if (!drv->glFormat) { 174 return; 175 } 176 177 if (!drv->renderTargetID) { 178 RSD_CALL_GL(glGenRenderbuffers, 1, &drv->renderTargetID); 179 180 if (!drv->renderTargetID) { 181 // This should generally not happen 182 ALOGE("allocateRenderTarget failed to gen mRenderTargetID"); 183 rsc->dumpDebug(); 184 return; 185 } 186 RSD_CALL_GL(glBindRenderbuffer, GL_RENDERBUFFER, drv->renderTargetID); 187 RSD_CALL_GL(glRenderbufferStorage, GL_RENDERBUFFER, drv->glFormat, 188 alloc->mHal.state.dimensionX, alloc->mHal.state.dimensionY); 189 } 190 rsdGLCheckError(rsc, "AllocateRenderTarget"); 191} 192 193static void UploadToBufferObject(const Context *rsc, const Allocation *alloc) { 194 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 195 196 rsAssert(!alloc->mHal.state.type->getDimY()); 197 rsAssert(!alloc->mHal.state.type->getDimZ()); 198 199 //alloc->mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX; 200 201 if (!drv->bufferID) { 202 RSD_CALL_GL(glGenBuffers, 1, &drv->bufferID); 203 } 204 if (!drv->bufferID) { 205 ALOGE("Upload to buffer object failed"); 206 drv->uploadDeferred = true; 207 return; 208 } 209 RSD_CALL_GL(glBindBuffer, drv->glTarget, drv->bufferID); 210 RSD_CALL_GL(glBufferData, drv->glTarget, alloc->mHal.state.type->getSizeBytes(), 211 drv->mallocPtr, GL_DYNAMIC_DRAW); 212 RSD_CALL_GL(glBindBuffer, drv->glTarget, 0); 213 rsdGLCheckError(rsc, "UploadToBufferObject"); 214} 215 216bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) { 217 DrvAllocation *drv = (DrvAllocation *)calloc(1, sizeof(DrvAllocation)); 218 if (!drv) { 219 return false; 220 } 221 222 void * ptr = malloc(alloc->mHal.state.type->getSizeBytes()); 223 if (!ptr) { 224 free(drv); 225 return false; 226 } 227 228 drv->glTarget = GL_NONE; 229 if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) { 230 if (alloc->mHal.state.hasFaces) { 231 drv->glTarget = GL_TEXTURE_CUBE_MAP; 232 } else { 233 drv->glTarget = GL_TEXTURE_2D; 234 } 235 } else { 236 if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) { 237 drv->glTarget = GL_ARRAY_BUFFER; 238 } 239 } 240 241 drv->glType = rsdTypeToGLType(alloc->mHal.state.type->getElement()->getComponent().getType()); 242 drv->glFormat = rsdKindToGLFormat(alloc->mHal.state.type->getElement()->getComponent().getKind()); 243 244 245 alloc->mHal.drvState.mallocPtr = ptr; 246 drv->mallocPtr = (uint8_t *)ptr; 247 alloc->mHal.drv = drv; 248 if (forceZero) { 249 memset(ptr, 0, alloc->mHal.state.type->getSizeBytes()); 250 } 251 252 if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) { 253 drv->uploadDeferred = true; 254 } 255 256 drv->readBackFBO = NULL; 257 258 return true; 259} 260 261void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) { 262 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 263 264 if (drv->bufferID) { 265 // Causes a SW crash.... 266 //ALOGV(" mBufferID %i", mBufferID); 267 //glDeleteBuffers(1, &mBufferID); 268 //mBufferID = 0; 269 } 270 if (drv->textureID) { 271 RSD_CALL_GL(glDeleteTextures, 1, &drv->textureID); 272 drv->textureID = 0; 273 } 274 if (drv->renderTargetID) { 275 RSD_CALL_GL(glDeleteRenderbuffers, 1, &drv->renderTargetID); 276 drv->renderTargetID = 0; 277 } 278 279 if (drv->mallocPtr) { 280 free(drv->mallocPtr); 281 drv->mallocPtr = NULL; 282 } 283 if (drv->readBackFBO != NULL) { 284 delete drv->readBackFBO; 285 drv->readBackFBO = NULL; 286 } 287 free(drv); 288 alloc->mHal.drv = NULL; 289} 290 291void rsdAllocationResize(const Context *rsc, const Allocation *alloc, 292 const Type *newType, bool zeroNew) { 293 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 294 295 drv->mallocPtr = (uint8_t *)realloc(drv->mallocPtr, newType->getSizeBytes()); 296 297 // fixme 298 ((Allocation *)alloc)->mHal.drvState.mallocPtr = drv->mallocPtr; 299 300 const uint32_t oldDimX = alloc->mHal.state.dimensionX; 301 const uint32_t dimX = newType->getDimX(); 302 303 if (dimX > oldDimX) { 304 const Element *e = alloc->mHal.state.type->getElement(); 305 uint32_t stride = e->getSizeBytes(); 306 memset(((uint8_t *)drv->mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX)); 307 } 308} 309 310static void rsdAllocationSyncFromFBO(const Context *rsc, const Allocation *alloc) { 311 if (!alloc->getIsScript()) { 312 return; // nothing to sync 313 } 314 315 RsdHal *dc = (RsdHal *)rsc->mHal.drv; 316 RsdFrameBufferObj *lastFbo = dc->gl.currentFrameBuffer; 317 318 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 319 if (!drv->textureID && !drv->renderTargetID) { 320 return; // nothing was rendered here yet, so nothing to sync 321 } 322 if (drv->readBackFBO == NULL) { 323 drv->readBackFBO = new RsdFrameBufferObj(); 324 drv->readBackFBO->setColorTarget(drv, 0); 325 drv->readBackFBO->setDimensions(alloc->getType()->getDimX(), 326 alloc->getType()->getDimY()); 327 } 328 329 // Bind the framebuffer object so we can read back from it 330 drv->readBackFBO->setActive(rsc); 331 332 // Do the readback 333 RSD_CALL_GL(glReadPixels, 0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(), 334 drv->glFormat, drv->glType, alloc->getPtr()); 335 336 // Revert framebuffer to its original 337 lastFbo->setActive(rsc); 338} 339 340 341void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc, 342 RsAllocationUsageType src) { 343 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 344 345 if (src == RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) { 346 if(!alloc->getIsRenderTarget()) { 347 rsc->setError(RS_ERROR_FATAL_DRIVER, 348 "Attempting to sync allocation from render target, " 349 "for non-render target allocation"); 350 } else if (alloc->getType()->getElement()->getKind() != RS_KIND_PIXEL_RGBA) { 351 rsc->setError(RS_ERROR_FATAL_DRIVER, "Cannot only sync from RGBA" 352 "render target"); 353 } else { 354 rsdAllocationSyncFromFBO(rsc, alloc); 355 } 356 return; 357 } 358 359 rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT); 360 361 if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) { 362 UploadToTexture(rsc, alloc); 363 } else { 364 if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) { 365 AllocateRenderTarget(rsc, alloc); 366 } 367 } 368 if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) { 369 UploadToBufferObject(rsc, alloc); 370 } 371 372 drv->uploadDeferred = false; 373} 374 375void rsdAllocationMarkDirty(const Context *rsc, const Allocation *alloc) { 376 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 377 drv->uploadDeferred = true; 378} 379 380int32_t rsdAllocationInitSurfaceTexture(const Context *rsc, const Allocation *alloc) { 381 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 382 UploadToTexture(rsc, alloc); 383 return drv->textureID; 384} 385 386void rsdAllocationData1D(const Context *rsc, const Allocation *alloc, 387 uint32_t xoff, uint32_t lod, uint32_t count, 388 const void *data, uint32_t sizeBytes) { 389 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 390 391 const uint32_t eSize = alloc->mHal.state.type->getElementSizeBytes(); 392 uint8_t * ptr = drv->mallocPtr; 393 ptr += eSize * xoff; 394 uint32_t size = count * eSize; 395 396 if (alloc->mHal.state.hasReferences) { 397 alloc->incRefs(data, count); 398 alloc->decRefs(ptr, count); 399 } 400 401 memcpy(ptr, data, size); 402 drv->uploadDeferred = true; 403} 404 405void rsdAllocationData2D(const Context *rsc, const Allocation *alloc, 406 uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face, 407 uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) { 408 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 409 410 uint32_t eSize = alloc->mHal.state.elementSizeBytes; 411 uint32_t lineSize = eSize * w; 412 uint32_t destW = alloc->mHal.state.dimensionX; 413 414 if (drv->mallocPtr) { 415 const uint8_t *src = static_cast<const uint8_t *>(data); 416 uint8_t *dst = drv->mallocPtr; 417 dst += alloc->mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff); 418 419 for (uint32_t line=yoff; line < (yoff+h); line++) { 420 if (alloc->mHal.state.hasReferences) { 421 alloc->incRefs(src, w); 422 alloc->decRefs(dst, w); 423 } 424 memcpy(dst, src, lineSize); 425 src += lineSize; 426 dst += destW * eSize; 427 } 428 drv->uploadDeferred = true; 429 } else { 430 Update2DTexture(rsc, alloc, data, xoff, yoff, lod, face, w, h); 431 } 432} 433 434void rsdAllocationData3D(const Context *rsc, const Allocation *alloc, 435 uint32_t xoff, uint32_t yoff, uint32_t zoff, 436 uint32_t lod, RsAllocationCubemapFace face, 437 uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) { 438 439} 440 441void rsdAllocationData1D_alloc(const android::renderscript::Context *rsc, 442 const android::renderscript::Allocation *dstAlloc, 443 uint32_t dstXoff, uint32_t dstLod, uint32_t count, 444 const android::renderscript::Allocation *srcAlloc, 445 uint32_t srcXoff, uint32_t srcLod) { 446} 447 448uint8_t *getOffsetPtr(const android::renderscript::Allocation *alloc, 449 uint32_t xoff, uint32_t yoff, uint32_t lod, 450 RsAllocationCubemapFace face) { 451 uint8_t *ptr = static_cast<uint8_t *>(alloc->getPtr()); 452 ptr += alloc->getType()->getLODOffset(lod, xoff, yoff); 453 454 if (face != 0) { 455 uint32_t totalSizeBytes = alloc->getType()->getSizeBytes(); 456 uint32_t faceOffset = totalSizeBytes / 6; 457 ptr += faceOffset * (uint32_t)face; 458 } 459 return ptr; 460} 461 462 463void rsdAllocationData2D_alloc_script(const android::renderscript::Context *rsc, 464 const android::renderscript::Allocation *dstAlloc, 465 uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod, 466 RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h, 467 const android::renderscript::Allocation *srcAlloc, 468 uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod, 469 RsAllocationCubemapFace srcFace) { 470 uint32_t elementSize = dstAlloc->getType()->getElementSizeBytes(); 471 for (uint32_t i = 0; i < h; i ++) { 472 uint8_t *dstPtr = getOffsetPtr(dstAlloc, dstXoff, dstYoff + i, dstLod, dstFace); 473 uint8_t *srcPtr = getOffsetPtr(srcAlloc, srcXoff, srcYoff + i, srcLod, srcFace); 474 memcpy(dstPtr, srcPtr, w * elementSize); 475 476 //ALOGE("COPIED dstXoff(%u), dstYoff(%u), dstLod(%u), dstFace(%u), w(%u), h(%u), srcXoff(%u), srcYoff(%u), srcLod(%u), srcFace(%u)", 477 // dstXoff, dstYoff, dstLod, dstFace, w, h, srcXoff, srcYoff, srcLod, srcFace); 478 } 479} 480 481void rsdAllocationData2D_alloc(const android::renderscript::Context *rsc, 482 const android::renderscript::Allocation *dstAlloc, 483 uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod, 484 RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h, 485 const android::renderscript::Allocation *srcAlloc, 486 uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod, 487 RsAllocationCubemapFace srcFace) { 488 if (!dstAlloc->getIsScript() && !srcAlloc->getIsScript()) { 489 rsc->setError(RS_ERROR_FATAL_DRIVER, "Non-script allocation copies not " 490 "yet implemented."); 491 return; 492 } 493 rsdAllocationData2D_alloc_script(rsc, dstAlloc, dstXoff, dstYoff, 494 dstLod, dstFace, w, h, srcAlloc, 495 srcXoff, srcYoff, srcLod, srcFace); 496} 497 498void rsdAllocationData3D_alloc(const android::renderscript::Context *rsc, 499 const android::renderscript::Allocation *dstAlloc, 500 uint32_t dstXoff, uint32_t dstYoff, uint32_t dstZoff, 501 uint32_t dstLod, RsAllocationCubemapFace dstFace, 502 uint32_t w, uint32_t h, uint32_t d, 503 const android::renderscript::Allocation *srcAlloc, 504 uint32_t srcXoff, uint32_t srcYoff, uint32_t srcZoff, 505 uint32_t srcLod, RsAllocationCubemapFace srcFace) { 506} 507 508void rsdAllocationElementData1D(const Context *rsc, const Allocation *alloc, 509 uint32_t x, 510 const void *data, uint32_t cIdx, uint32_t sizeBytes) { 511 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 512 513 uint32_t eSize = alloc->mHal.state.elementSizeBytes; 514 uint8_t * ptr = drv->mallocPtr; 515 ptr += eSize * x; 516 517 const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx); 518 ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); 519 520 if (alloc->mHal.state.hasReferences) { 521 e->incRefs(data); 522 e->decRefs(ptr); 523 } 524 525 memcpy(ptr, data, sizeBytes); 526 drv->uploadDeferred = true; 527} 528 529void rsdAllocationElementData2D(const Context *rsc, const Allocation *alloc, 530 uint32_t x, uint32_t y, 531 const void *data, uint32_t cIdx, uint32_t sizeBytes) { 532 DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv; 533 534 uint32_t eSize = alloc->mHal.state.elementSizeBytes; 535 uint8_t * ptr = drv->mallocPtr; 536 ptr += eSize * (x + y * alloc->mHal.state.dimensionX); 537 538 const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx); 539 ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx); 540 541 if (alloc->mHal.state.hasReferences) { 542 e->incRefs(data); 543 e->decRefs(ptr); 544 } 545 546 memcpy(ptr, data, sizeBytes); 547 drv->uploadDeferred = true; 548} 549 550 551