Allocation.cpp revision e5428e661ce6f9d24f838cab0a8fb0fa8c76dbca
1/* 2 * Copyright (C) 2013 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 "RenderScript.h" 18#include "rsCppInternal.h" 19 20using namespace android; 21using namespace RSC; 22 23void * Allocation::getIDSafe() const { 24 return getID(); 25} 26 27void Allocation::updateCacheInfo(sp<const Type> t) { 28 mCurrentDimX = t->getX(); 29 mCurrentDimY = t->getY(); 30 mCurrentDimZ = t->getZ(); 31 mCurrentCount = mCurrentDimX; 32 if (mCurrentDimY > 1) { 33 mCurrentCount *= mCurrentDimY; 34 } 35 if (mCurrentDimZ > 1) { 36 mCurrentCount *= mCurrentDimZ; 37 } 38} 39 40Allocation::Allocation(void *id, sp<RS> rs, sp<const Type> t, uint32_t usage) : 41 BaseObj(id, rs), mSelectedY(0), mSelectedZ(0), mSelectedLOD(0), 42 mSelectedFace(RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X) { 43 44 if ((usage & ~(RS_ALLOCATION_USAGE_SCRIPT | 45 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE | 46 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX | 47 RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS | 48 RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET | 49 RS_ALLOCATION_USAGE_IO_INPUT | 50 RS_ALLOCATION_USAGE_IO_OUTPUT | 51 RS_ALLOCATION_USAGE_SHARED)) != 0) { 52 ALOGE("Unknown usage specified."); 53 } 54 55 if ((usage & RS_ALLOCATION_USAGE_IO_INPUT) != 0) { 56 mWriteAllowed = false; 57 if ((usage & ~(RS_ALLOCATION_USAGE_IO_INPUT | 58 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE | 59 RS_ALLOCATION_USAGE_SCRIPT)) != 0) { 60 ALOGE("Invalid usage combination."); 61 } 62 } 63 64 mType = t; 65 mUsage = usage; 66 mAutoPadding = false; 67 if (t != nullptr) { 68 updateCacheInfo(t); 69 } 70 71} 72 73 74void Allocation::validateIsInt64() { 75 RsDataType dt = mType->getElement()->getDataType(); 76 if ((dt == RS_TYPE_SIGNED_64) || (dt == RS_TYPE_UNSIGNED_64)) { 77 return; 78 } 79 ALOGE("64 bit integer source does not match allocation type %i", dt); 80} 81 82void Allocation::validateIsInt32() { 83 RsDataType dt = mType->getElement()->getDataType(); 84 if ((dt == RS_TYPE_SIGNED_32) || (dt == RS_TYPE_UNSIGNED_32)) { 85 return; 86 } 87 ALOGE("32 bit integer source does not match allocation type %i", dt); 88} 89 90void Allocation::validateIsInt16() { 91 RsDataType dt = mType->getElement()->getDataType(); 92 if ((dt == RS_TYPE_SIGNED_16) || (dt == RS_TYPE_UNSIGNED_16)) { 93 return; 94 } 95 ALOGE("16 bit integer source does not match allocation type %i", dt); 96} 97 98void Allocation::validateIsInt8() { 99 RsDataType dt = mType->getElement()->getDataType(); 100 if ((dt == RS_TYPE_SIGNED_8) || (dt == RS_TYPE_UNSIGNED_8)) { 101 return; 102 } 103 ALOGE("8 bit integer source does not match allocation type %i", dt); 104} 105 106void Allocation::validateIsFloat32() { 107 RsDataType dt = mType->getElement()->getDataType(); 108 if (dt == RS_TYPE_FLOAT_32) { 109 return; 110 } 111 ALOGE("32 bit float source does not match allocation type %i", dt); 112} 113 114void Allocation::validateIsFloat64() { 115 RsDataType dt = mType->getElement()->getDataType(); 116 if (dt == RS_TYPE_FLOAT_64) { 117 return; 118 } 119 ALOGE("64 bit float source does not match allocation type %i", dt); 120} 121 122void Allocation::validateIsObject() { 123 RsDataType dt = mType->getElement()->getDataType(); 124 if ((dt == RS_TYPE_ELEMENT) || 125 (dt == RS_TYPE_TYPE) || 126 (dt == RS_TYPE_ALLOCATION) || 127 (dt == RS_TYPE_SAMPLER) || 128 (dt == RS_TYPE_SCRIPT) || 129 (dt == RS_TYPE_MESH) || 130 (dt == RS_TYPE_PROGRAM_FRAGMENT) || 131 (dt == RS_TYPE_PROGRAM_VERTEX) || 132 (dt == RS_TYPE_PROGRAM_RASTER) || 133 (dt == RS_TYPE_PROGRAM_STORE)) { 134 return; 135 } 136 ALOGE("Object source does not match allocation type %i", dt); 137} 138 139void Allocation::updateFromNative() { 140 BaseObj::updateFromNative(); 141 142 const void *typeID = RS::dispatch->AllocationGetType(mRS->getContext(), getID()); 143 if(typeID != nullptr) { 144 sp<const Type> old = mType; 145 sp<Type> t = new Type((void *)typeID, mRS); 146 t->updateFromNative(); 147 updateCacheInfo(t); 148 mType = t; 149 } 150} 151 152void Allocation::syncAll(RsAllocationUsageType srcLocation) { 153 switch (srcLocation) { 154 case RS_ALLOCATION_USAGE_SCRIPT: 155 case RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS: 156 case RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE: 157 case RS_ALLOCATION_USAGE_GRAPHICS_VERTEX: 158 case RS_ALLOCATION_USAGE_SHARED: 159 break; 160 default: 161 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Source must be exactly one usage type."); 162 return; 163 } 164 tryDispatch(mRS, RS::dispatch->AllocationSyncAll(mRS->getContext(), getIDSafe(), srcLocation)); 165} 166 167void Allocation::ioSendOutput() { 168//TODO: Also make it able to use for compatlib. 169#ifndef RS_COMPATIBILITY_LIB 170 if ((mUsage & RS_ALLOCATION_USAGE_IO_OUTPUT) == 0) { 171 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only send buffer if IO_OUTPUT usage specified."); 172 return; 173 } 174 tryDispatch(mRS, RS::dispatch->AllocationIoSend(mRS->getContext(), getID())); 175#endif 176} 177 178void Allocation::ioGetInput() { 179#ifndef RS_COMPATIBILITY_LIB 180 if ((mUsage & RS_ALLOCATION_USAGE_IO_INPUT) == 0) { 181 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only get buffer if IO_INPUT usage specified."); 182 return; 183 } 184 tryDispatch(mRS, RS::dispatch->AllocationIoReceive(mRS->getContext(), getID())); 185#endif 186} 187 188void * Allocation::getPointer(size_t *stride) { 189 void *p = nullptr; 190 if (!(mUsage & RS_ALLOCATION_USAGE_SHARED)) { 191 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Allocation does not support USAGE_SHARED."); 192 return nullptr; 193 } 194 195 // FIXME: decide if lack of getPointer should cause compat mode 196 if (RS::dispatch->AllocationGetPointer == nullptr) { 197 mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Can't use getPointer on older APIs"); 198 return nullptr; 199 } 200 201 p = RS::dispatch->AllocationGetPointer(mRS->getContext(), getIDSafe(), 0, 202 RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0, stride, sizeof(size_t)); 203 if (mRS->getError() != RS_SUCCESS) { 204 mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation lock failed"); 205 p = nullptr; 206 } 207 return p; 208} 209 210// --------------------------------------------------------------------------- 211//Functions needed for autopadding & unpadding 212static void copyWithPadding(void* ptr, const void* srcPtr, int mSize, int count) { 213 int sizeBytesPad = mSize * 4; 214 int sizeBytes = mSize * 3; 215 uint8_t *dst = static_cast<uint8_t *>(ptr); 216 const uint8_t *src = static_cast<const uint8_t *>(srcPtr); 217 for (int i = 0; i < count; i++) { 218 memcpy(dst, src, sizeBytes); 219 dst += sizeBytesPad; 220 src += sizeBytes; 221 } 222} 223 224static void copyWithUnPadding(void* ptr, const void* srcPtr, int mSize, int count) { 225 int sizeBytesPad = mSize * 4; 226 int sizeBytes = mSize * 3; 227 uint8_t *dst = static_cast<uint8_t *>(ptr); 228 const uint8_t *src = static_cast<const uint8_t *>(srcPtr); 229 for (int i = 0; i < count; i++) { 230 memcpy(dst, src, sizeBytes); 231 dst += sizeBytes; 232 src += sizeBytesPad; 233 } 234} 235// --------------------------------------------------------------------------- 236 237void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const void *data) { 238 239 if(count < 1) { 240 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1."); 241 return; 242 } 243 if((off + count) > mCurrentCount) { 244 ALOGE("Overflow, Available count %u, got %zu at offset %u.", mCurrentCount, count, off); 245 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified"); 246 return; 247 } 248 if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) { 249 size_t eSize = mType->getElement()->getSizeBytes(); 250 void *ptr = malloc(eSize * count); 251 copyWithPadding(ptr, data, eSize / 4, count); 252 tryDispatch(mRS, RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD, 253 count, ptr, count * mType->getElement()->getSizeBytes())); 254 free(ptr); 255 } else { 256 tryDispatch(mRS, RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD, 257 count, data, count * mType->getElement()->getSizeBytes())); 258 } 259} 260 261void Allocation::copy1DRangeTo(uint32_t off, size_t count, void *data) { 262 if(count < 1) { 263 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1."); 264 return; 265 } 266 if((off + count) > mCurrentCount) { 267 ALOGE("Overflow, Available count %u, got %zu at offset %u.", mCurrentCount, count, off); 268 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified"); 269 return; 270 } 271 if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) { 272 size_t eSize = mType->getElement()->getSizeBytes(); 273 void *ptr = malloc(eSize * count); 274 tryDispatch(mRS, RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD, 275 count, ptr, count * mType->getElement()->getSizeBytes())); 276 copyWithUnPadding(data, ptr, eSize / 4, count); 277 free(ptr); 278 } else { 279 tryDispatch(mRS, RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD, 280 count, data, count * mType->getElement()->getSizeBytes())); 281 } 282} 283 284void Allocation::copy1DRangeFrom(uint32_t off, size_t count, sp<const Allocation> data, 285 uint32_t dataOff) { 286 287 tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), off, 0, 288 mSelectedLOD, mSelectedFace, 289 count, 1, data->getIDSafe(), dataOff, 0, 290 data->mSelectedLOD, data->mSelectedFace)); 291} 292 293void Allocation::copy1DFrom(const void* data) { 294 copy1DRangeFrom(0, mCurrentCount, data); 295} 296 297void Allocation::copy1DTo(void* data) { 298 copy1DRangeTo(0, mCurrentCount, data); 299} 300 301 302void Allocation::validate2DRange(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h) { 303 if (mAdaptedAllocation != nullptr) { 304 305 } else { 306 if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) { 307 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation."); 308 } 309 } 310} 311 312void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, 313 const void *data) { 314 validate2DRange(xoff, yoff, w, h); 315 if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) { 316 size_t eSize = mType->getElement()->getSizeBytes(); 317 void *ptr = malloc(eSize * w * h); 318 copyWithPadding(ptr, data, eSize / 4, w * h); 319 tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, 320 yoff, mSelectedLOD, mSelectedFace, 321 w, h, ptr, w * h * mType->getElement()->getSizeBytes(), 322 w * mType->getElement()->getSizeBytes())); 323 free(ptr); 324 } else { 325 tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, 326 yoff, mSelectedLOD, mSelectedFace, 327 w, h, data, w * h * mType->getElement()->getSizeBytes(), 328 w * mType->getElement()->getSizeBytes())); 329 } 330} 331 332void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, 333 sp<const Allocation> data, uint32_t dataXoff, uint32_t dataYoff) { 334 validate2DRange(xoff, yoff, w, h); 335 tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), xoff, yoff, 336 mSelectedLOD, mSelectedFace, 337 w, h, data->getIDSafe(), dataXoff, dataYoff, 338 data->mSelectedLOD, data->mSelectedFace)); 339} 340 341void Allocation::copy2DRangeTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, 342 void* data) { 343 validate2DRange(xoff, yoff, w, h); 344 if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) { 345 size_t eSize = mType->getElement()->getSizeBytes(); 346 void *ptr = malloc(eSize * w * h); 347 tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, 348 mSelectedLOD, mSelectedFace, w, h, ptr, 349 w * h * mType->getElement()->getSizeBytes(), 350 w * mType->getElement()->getSizeBytes())); 351 copyWithUnPadding(data, ptr, eSize / 4, w * h); 352 free(ptr); 353 } else { 354 tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, 355 mSelectedLOD, mSelectedFace, w, h, data, 356 w * h * mType->getElement()->getSizeBytes(), 357 w * mType->getElement()->getSizeBytes())); 358 } 359} 360 361void Allocation::copy2DStridedFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, 362 const void *data, size_t stride) { 363 validate2DRange(xoff, yoff, w, h); 364 tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff, 365 mSelectedLOD, mSelectedFace, w, h, data, 366 w * h * mType->getElement()->getSizeBytes(), stride)); 367} 368 369void Allocation::copy2DStridedFrom(const void* data, size_t stride) { 370 copy2DStridedFrom(0, 0, mCurrentDimX, mCurrentDimY, data, stride); 371} 372 373void Allocation::copy2DStridedTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, 374 void *data, size_t stride) { 375 validate2DRange(xoff, yoff, w, h); 376 tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, 377 mSelectedLOD, mSelectedFace, w, h, data, 378 w * h * mType->getElement()->getSizeBytes(), stride)); 379} 380 381void Allocation::copy2DStridedTo(void* data, size_t stride) { 382 copy2DStridedTo(0, 0, mCurrentDimX, mCurrentDimY, data, stride); 383} 384 385void Allocation::validate3DRange(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, 386 uint32_t h, uint32_t d) { 387 if (mAdaptedAllocation != nullptr) { 388 389 } else { 390 if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) { 391 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation."); 392 } 393 } 394} 395 396void Allocation::copy3DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, 397 uint32_t h, uint32_t d, const void* data) { 398 validate3DRange(xoff, yoff, zoff, w, h, d); 399 if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) { 400 size_t eSize = mType->getElement()->getSizeBytes(); 401 void *ptr = malloc(eSize * w * h * d); 402 copyWithPadding(ptr, data, eSize / 4, w * h * d); 403 tryDispatch(mRS, RS::dispatch->Allocation3DData(mRS->getContext(), getIDSafe(), xoff, yoff, zoff, 404 mSelectedLOD, w, h, d, ptr, 405 w * h * d * mType->getElement()->getSizeBytes(), 406 w * mType->getElement()->getSizeBytes())); 407 free(ptr); 408 } else { 409 tryDispatch(mRS, RS::dispatch->Allocation3DData(mRS->getContext(), getIDSafe(), xoff, yoff, zoff, 410 mSelectedLOD, w, h, d, data, 411 w * h * d * mType->getElement()->getSizeBytes(), 412 w * mType->getElement()->getSizeBytes())); 413 } 414} 415 416void Allocation::copy3DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, uint32_t h, uint32_t d, 417 sp<const Allocation> data, uint32_t dataXoff, uint32_t dataYoff, uint32_t dataZoff) { 418 validate3DRange(xoff, yoff, zoff, w, h, d); 419 tryDispatch(mRS, RS::dispatch->AllocationCopy3DRange(mRS->getContext(), getIDSafe(), xoff, yoff, zoff, 420 mSelectedLOD, w, h, d, data->getIDSafe(), 421 dataXoff, dataYoff, dataZoff, data->mSelectedLOD)); 422} 423 424void Allocation::copy3DRangeTo(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, 425 uint32_t h, uint32_t d, void* data) { 426 validate3DRange(xoff, yoff, zoff, w, h, d); 427 if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) { 428 size_t eSize = mType->getElement()->getSizeBytes(); 429 void *ptr = malloc(eSize * w * h * d); 430 tryDispatch(mRS, RS::dispatch->Allocation3DRead(mRS->getContext(), getIDSafe(), xoff, yoff, zoff, 431 mSelectedLOD, w, h, d, ptr, 432 w * h * d * mType->getElement()->getSizeBytes(), 433 w * mType->getElement()->getSizeBytes())); 434 copyWithUnPadding(data, ptr, eSize / 4, w * h * d); 435 free(ptr); 436 } else { 437 tryDispatch(mRS, RS::dispatch->Allocation3DRead(mRS->getContext(), getIDSafe(), xoff, yoff, zoff, 438 mSelectedLOD, w, h, d, data, 439 w * h * d * mType->getElement()->getSizeBytes(), 440 w * mType->getElement()->getSizeBytes())); 441 } 442} 443 444sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type, 445 RsAllocationMipmapControl mipmaps, uint32_t usage) { 446 void *id = 0; 447 if (rs->getError() == RS_SUCCESS) { 448 id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mipmaps, usage, 0); 449 } 450 if (id == 0) { 451 rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed"); 452 return nullptr; 453 } 454 return new Allocation(id, rs, type, usage); 455} 456 457sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type, 458 RsAllocationMipmapControl mipmaps, uint32_t usage, 459 void *pointer) { 460 void *id = 0; 461 if (rs->getError() == RS_SUCCESS) { 462 id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mipmaps, usage, 463 (uintptr_t)pointer); 464 } 465 if (id == 0) { 466 rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed"); 467 return nullptr; 468 } 469 return new Allocation(id, rs, type, usage); 470} 471 472sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type, 473 uint32_t usage) { 474 return createTyped(rs, type, RS_ALLOCATION_MIPMAP_NONE, usage); 475} 476 477sp<Allocation> Allocation::createSized(sp<RS> rs, sp<const Element> e, 478 size_t count, uint32_t usage) { 479 Type::Builder b(rs, e); 480 b.setX(count); 481 sp<const Type> t = b.create(); 482 483 return createTyped(rs, t, usage); 484} 485 486sp<Allocation> Allocation::createSized2D(sp<RS> rs, sp<const Element> e, 487 size_t x, size_t y, uint32_t usage) { 488 Type::Builder b(rs, e); 489 b.setX(x); 490 b.setY(y); 491 sp<const Type> t = b.create(); 492 493 return createTyped(rs, t, usage); 494} 495