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 20 using namespace android; 21 using namespace RSC; 22 23 void * Allocation::getIDSafe() const { 24 return getID(); 25 } 26 27 void 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 40 Allocation::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 67 if (t != NULL) { 68 updateCacheInfo(t); 69 } 70 71 } 72 73 74 75 void Allocation::validateIsInt32() { 76 RsDataType dt = mType->getElement()->getDataType(); 77 if ((dt == RS_TYPE_SIGNED_32) || (dt == RS_TYPE_UNSIGNED_32)) { 78 return; 79 } 80 ALOGE("32 bit integer source does not match allocation type %i", dt); 81 } 82 83 void Allocation::validateIsInt16() { 84 RsDataType dt = mType->getElement()->getDataType(); 85 if ((dt == RS_TYPE_SIGNED_16) || (dt == RS_TYPE_UNSIGNED_16)) { 86 return; 87 } 88 ALOGE("16 bit integer source does not match allocation type %i", dt); 89 } 90 91 void Allocation::validateIsInt8() { 92 RsDataType dt = mType->getElement()->getDataType(); 93 if ((dt == RS_TYPE_SIGNED_8) || (dt == RS_TYPE_UNSIGNED_8)) { 94 return; 95 } 96 ALOGE("8 bit integer source does not match allocation type %i", dt); 97 } 98 99 void Allocation::validateIsFloat32() { 100 RsDataType dt = mType->getElement()->getDataType(); 101 if (dt == RS_TYPE_FLOAT_32) { 102 return; 103 } 104 ALOGE("32 bit float source does not match allocation type %i", dt); 105 } 106 107 void Allocation::validateIsObject() { 108 RsDataType dt = mType->getElement()->getDataType(); 109 if ((dt == RS_TYPE_ELEMENT) || 110 (dt == RS_TYPE_TYPE) || 111 (dt == RS_TYPE_ALLOCATION) || 112 (dt == RS_TYPE_SAMPLER) || 113 (dt == RS_TYPE_SCRIPT) || 114 (dt == RS_TYPE_MESH) || 115 (dt == RS_TYPE_PROGRAM_FRAGMENT) || 116 (dt == RS_TYPE_PROGRAM_VERTEX) || 117 (dt == RS_TYPE_PROGRAM_RASTER) || 118 (dt == RS_TYPE_PROGRAM_STORE)) { 119 return; 120 } 121 ALOGE("Object source does not match allocation type %i", dt); 122 } 123 124 void Allocation::updateFromNative() { 125 BaseObj::updateFromNative(); 126 127 const void *typeID = RS::dispatch->AllocationGetType(mRS->getContext(), getID()); 128 if(typeID != NULL) { 129 sp<const Type> old = mType; 130 sp<Type> t = new Type((void *)typeID, mRS); 131 t->updateFromNative(); 132 updateCacheInfo(t); 133 mType = t; 134 } 135 } 136 137 void Allocation::syncAll(RsAllocationUsageType srcLocation) { 138 switch (srcLocation) { 139 case RS_ALLOCATION_USAGE_SCRIPT: 140 case RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS: 141 case RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE: 142 case RS_ALLOCATION_USAGE_GRAPHICS_VERTEX: 143 case RS_ALLOCATION_USAGE_SHARED: 144 break; 145 default: 146 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Source must be exactly one usage type."); 147 return; 148 } 149 tryDispatch(mRS, RS::dispatch->AllocationSyncAll(mRS->getContext(), getIDSafe(), srcLocation)); 150 } 151 152 void Allocation::ioSendOutput() { 153 #ifndef RS_COMPATIBILITY_LIB 154 if ((mUsage & RS_ALLOCATION_USAGE_IO_OUTPUT) == 0) { 155 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only send buffer if IO_OUTPUT usage specified."); 156 return; 157 } 158 tryDispatch(mRS, RS::dispatch->AllocationIoSend(mRS->getContext(), getID())); 159 #endif 160 } 161 162 void Allocation::ioGetInput() { 163 #ifndef RS_COMPATIBILITY_LIB 164 if ((mUsage & RS_ALLOCATION_USAGE_IO_INPUT) == 0) { 165 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only send buffer if IO_OUTPUT usage specified."); 166 return; 167 } 168 tryDispatch(mRS, RS::dispatch->AllocationIoReceive(mRS->getContext(), getID())); 169 #endif 170 } 171 172 void * Allocation::getPointer(size_t *stride) { 173 void *p = NULL; 174 if (!(mUsage & RS_ALLOCATION_USAGE_SHARED)) { 175 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Allocation does not support USAGE_SHARED."); 176 return NULL; 177 } 178 179 // FIXME: decide if lack of getPointer should cause compat mode 180 if (RS::dispatch->AllocationGetPointer == NULL) { 181 mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Can't use getPointer on older APIs"); 182 return NULL; 183 } 184 185 p = RS::dispatch->AllocationGetPointer(mRS->getContext(), getIDSafe(), 0, 186 RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0, stride); 187 if (mRS->getError() != RS_SUCCESS) { 188 mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation lock failed"); 189 p = NULL; 190 } 191 return p; 192 } 193 194 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const void *data) { 195 196 if(count < 1) { 197 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1."); 198 return; 199 } 200 if((off + count) > mCurrentCount) { 201 ALOGE("Overflow, Available count %u, got %zu at offset %u.", mCurrentCount, count, off); 202 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified"); 203 return; 204 } 205 206 tryDispatch(mRS, RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD, 207 count, data, count * mType->getElement()->getSizeBytes())); 208 } 209 210 void Allocation::copy1DRangeTo(uint32_t off, size_t count, void *data) { 211 if(count < 1) { 212 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1."); 213 return; 214 } 215 if((off + count) > mCurrentCount) { 216 ALOGE("Overflow, Available count %u, got %zu at offset %u.", mCurrentCount, count, off); 217 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified"); 218 return; 219 } 220 221 tryDispatch(mRS, RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD, 222 count, data, count * mType->getElement()->getSizeBytes())); 223 } 224 225 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, sp<const Allocation> data, 226 uint32_t dataOff) { 227 228 tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), off, 0, 229 mSelectedLOD, mSelectedFace, 230 count, 1, data->getIDSafe(), dataOff, 0, 231 data->mSelectedLOD, data->mSelectedFace)); 232 } 233 234 void Allocation::copy1DFrom(const void* data) { 235 copy1DRangeFrom(0, mCurrentCount, data); 236 } 237 238 void Allocation::copy1DTo(void* data) { 239 copy1DRangeTo(0, mCurrentCount, data); 240 } 241 242 243 void Allocation::validate2DRange(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h) { 244 if (mAdaptedAllocation != NULL) { 245 246 } else { 247 if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) { 248 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation."); 249 } 250 } 251 } 252 253 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, 254 const void *data) { 255 validate2DRange(xoff, yoff, w, h); 256 tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, 257 yoff, mSelectedLOD, mSelectedFace, 258 w, h, data, w * h * mType->getElement()->getSizeBytes(), 259 w * mType->getElement()->getSizeBytes())); 260 } 261 262 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, 263 sp<const Allocation> data, uint32_t dataXoff, uint32_t dataYoff) { 264 validate2DRange(xoff, yoff, w, h); 265 tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), xoff, yoff, 266 mSelectedLOD, mSelectedFace, 267 w, h, data->getIDSafe(), dataXoff, dataYoff, 268 data->mSelectedLOD, data->mSelectedFace)); 269 } 270 271 void Allocation::copy2DRangeTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, 272 void* data) { 273 validate2DRange(xoff, yoff, w, h); 274 tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, 275 mSelectedLOD, mSelectedFace, w, h, data, 276 w * h * mType->getElement()->getSizeBytes(), 277 w * mType->getElement()->getSizeBytes())); 278 } 279 280 void Allocation::copy2DStridedFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, 281 const void *data, size_t stride) { 282 validate2DRange(xoff, yoff, w, h); 283 tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff, 284 mSelectedLOD, mSelectedFace, w, h, data, 285 w * h * mType->getElement()->getSizeBytes(), stride)); 286 } 287 288 void Allocation::copy2DStridedFrom(const void* data, size_t stride) { 289 copy2DStridedFrom(0, 0, mCurrentDimX, mCurrentDimY, data, stride); 290 } 291 292 void Allocation::copy2DStridedTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, 293 void *data, size_t stride) { 294 validate2DRange(xoff, yoff, w, h); 295 tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, 296 mSelectedLOD, mSelectedFace, w, h, data, 297 w * h * mType->getElement()->getSizeBytes(), stride)); 298 } 299 300 void Allocation::copy2DStridedTo(void* data, size_t stride) { 301 copy2DStridedTo(0, 0, mCurrentDimX, mCurrentDimY, data, stride); 302 } 303 304 void Allocation::validate3DRange(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, 305 uint32_t h, uint32_t d) { 306 if (mAdaptedAllocation != NULL) { 307 308 } else { 309 if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) { 310 mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation."); 311 } 312 } 313 } 314 315 void Allocation::copy3DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, 316 uint32_t h, uint32_t d, const void* data) { 317 validate3DRange(xoff, yoff, zoff, w, h, d); 318 tryDispatch(mRS, RS::dispatch->Allocation3DData(mRS->getContext(), getIDSafe(), xoff, yoff, zoff, 319 mSelectedLOD, w, h, d, data, 320 w * h * d * mType->getElement()->getSizeBytes(), 321 w * mType->getElement()->getSizeBytes())); 322 } 323 324 void Allocation::copy3DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, uint32_t h, uint32_t d, 325 sp<const Allocation> data, uint32_t dataXoff, uint32_t dataYoff, uint32_t dataZoff) { 326 validate3DRange(xoff, yoff, zoff, dataXoff, dataYoff, dataZoff); 327 tryDispatch(mRS, RS::dispatch->AllocationCopy3DRange(mRS->getContext(), getIDSafe(), xoff, yoff, zoff, 328 mSelectedLOD, w, h, d, data->getIDSafe(), 329 dataXoff, dataYoff, dataZoff, data->mSelectedLOD)); 330 } 331 332 333 sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type, 334 RsAllocationMipmapControl mipmaps, uint32_t usage) { 335 void *id = 0; 336 if (rs->getError() == RS_SUCCESS) { 337 id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mipmaps, usage, 0); 338 } 339 if (id == 0) { 340 rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed"); 341 return NULL; 342 } 343 return new Allocation(id, rs, type, usage); 344 } 345 346 sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type, 347 RsAllocationMipmapControl mipmaps, uint32_t usage, 348 void *pointer) { 349 void *id = 0; 350 if (rs->getError() == RS_SUCCESS) { 351 id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mipmaps, usage, 352 (uintptr_t)pointer); 353 } 354 if (id == 0) { 355 rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed"); 356 return NULL; 357 } 358 return new Allocation(id, rs, type, usage); 359 } 360 361 sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type, 362 uint32_t usage) { 363 return createTyped(rs, type, RS_ALLOCATION_MIPMAP_NONE, usage); 364 } 365 366 sp<Allocation> Allocation::createSized(sp<RS> rs, sp<const Element> e, 367 size_t count, uint32_t usage) { 368 Type::Builder b(rs, e); 369 b.setX(count); 370 sp<const Type> t = b.create(); 371 372 return createTyped(rs, t, usage); 373 } 374 375 sp<Allocation> Allocation::createSized2D(sp<RS> rs, sp<const Element> e, 376 size_t x, size_t y, uint32_t usage) { 377 Type::Builder b(rs, e); 378 b.setX(x); 379 b.setY(y); 380 sp<const Type> t = b.create(); 381 382 return createTyped(rs, t, usage); 383 } 384