in RenderScriptMigrationSample/app/src/main/cpp/VulkanResources.cpp [151:194]
bool Image::setContentFromBitmap(JNIEnv* env, jobject bitmap) {
// Get bitmap info
AndroidBitmapInfo info;
RET_CHECK(AndroidBitmap_getInfo(env, bitmap, &info) == ANDROID_BITMAP_RESULT_SUCCESS);
RET_CHECK(info.width == mWidth);
RET_CHECK(info.height == mHeight);
RET_CHECK(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888);
RET_CHECK(info.stride % 4 == 0);
// Allocate a staging buffer
const uint32_t bufferSize = info.stride * info.height;
auto stagingBuffer = Buffer::create(
mContext, bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
// Copy bitmap pixels to the buffer memory
void* bitmapData = nullptr;
RET_CHECK(AndroidBitmap_lockPixels(env, bitmap, &bitmapData) == ANDROID_BITMAP_RESULT_SUCCESS);
const bool success = stagingBuffer->copyFrom(bitmapData);
AndroidBitmap_unlockPixels(env, bitmap);
RET_CHECK(success);
// Set layout to VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL to prepare for buffer-image copy
RET_CHECK(transitionLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL));
// Copy buffer to image
VulkanCommandBuffer copyCommand(mContext->device(), mContext->commandPool());
RET_CHECK(mContext->beginSingleTimeCommand(copyCommand.pHandle()));
const VkBufferImageCopy bufferImageCopy = {
.bufferOffset = 0,
.bufferRowLength = info.stride / 4,
.bufferImageHeight = mHeight,
.imageSubresource = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
.imageOffset = {0, 0, 0},
.imageExtent = {mWidth, mHeight, 1},
};
vkCmdCopyBufferToImage(copyCommand.handle(), stagingBuffer->getBufferHandle(), mImage.handle(),
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferImageCopy);
RET_CHECK(mContext->endAndSubmitSingleTimeCommand(copyCommand.handle()));
// Set layout to VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL to prepare for input sampler usage
RET_CHECK(transitionLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL));
return true;
}