void TextureLoader::create( const unsigned int _width, const unsigned int _height, const TEXTURE_FORMAT _textureFormat, const bool _createMipLevels ) { // argument checks if ( _width < 1 ) GEM_ERROR( "Invalid texture width " + _width ); if ( _height < 1 ) GEM_ERROR( "Invalid texture height " + _height ); if ( _textureFormat == TEXTURE_FORMAT_NONE ) GEM_ERROR( "Invalid texture format " + _textureFormat ); // always create new if ( isLoaded_ ) clear( ); // allocate memory for first mip level try { if ( _createMipLevels ) { createMipLevels( _width, _height, _textureFormat, MAX_MIP_LEVELS ); } else { createMipLevels( _width, _height, _textureFormat, 1 ); } } catch( const std::exception &e ) { clear(); GEM_ERROR( e.what() ); } // we got this far, so we are ok to setup member variables isLoaded_ = true; }
void TextureLoader::loadDDS( const std::string& _path ) { // local vars std::ifstream ifs; DDSHEADER ddshdr; // open file for reading ifs.open( _path.c_str(), std::ifstream::in | std::ifstream::binary ); if ( ifs.fail() ) { GEM_THROW( "Could not open file " + _path ); } // read dds header ifs.read( reinterpret_cast<char*>(&ddshdr), sizeof( DDSHEADER ) ); if ( ifs.fail( ) ) { ifs.close(); GEM_THROW( "Failed to read image file header." ); } // make sure its a .dds file if ( ddshdr.type == "DDS " ) { ifs.close(); GEM_THROW( "File is not a DDS file." ); } // DXT1 format if ( ddshdr.pixelFormat.fourCC==FOURCC_DXT1 ) { // allocate data createMipLevels( ddshdr.width, ddshdr.height, TEXTURE_FORMAT_RGB_DXT1, ddshdr.mipMapCount ); // read image data for each mipmap for ( unsigned int i=0; i<mipLevelCount_; ++i ) { // get character ptr and total bytecount char* ptr = mipLevels_[i].getWritePtr<char>(); int bytecount = mipLevels_[i].getByteCount(); ifs.read( ptr, bytecount ); if ( ifs.fail() ) { ifs.close(); GEM_THROW( "Failed to read image data." ); } } } // format not supported else { ifs.close(); GEM_THROW( "This file is not a DXT1 file." ); } // close file and return ifs.close(); }
void TextureLoader::loadPFM( const std::string& _path ) { // local vars PFMHEADER hdr; std::ifstream ifs; char ignore; // open file for reading ifs.open( _path.c_str(), std::ifstream::in | std::ifstream::binary ); if ( ifs.fail() ) { GEM_THROW( "Could not open file " + _path ); } // get header info ifs >> hdr.p >> hdr.f // identifier line >> hdr.width >> hdr.height // dimension line >> hdr.scalefactor; // scale/endianess line ifs.getline( &ignore, 1 ); // chew last linefeed if ( hdr.p!='P' || ( hdr.f!='F' && hdr .f!='f' ) ) { ifs.close(); GEM_THROW( "Failed to read image header." ); } // 32-bit/channel floating point RGB if ( hdr.f=='F' ) { // allocate data createMipLevels( hdr.width, hdr.height, TEXTURE_FORMAT_RGB_32F, 1 ); // get character ptr and total bytecount char* ptr = mipLevels_[0].getWritePtr<char>(); int bytecount = mipLevels_[0].getByteCount(); // read floating point data from file ifs.read( ptr, bytecount ); if ( ifs.fail() ) { ifs.close(); GEM_THROW( "Failed to read image data." ); } } // 32-bit/channel floating point monochrome else { // set variables and allocate data createMipLevels( hdr.width, hdr.height, TEXTURE_FORMAT_R_32F, 1 ); char* ptr = mipLevels_[0].getWritePtr<char>(); int bytecount = mipLevels_[0].getByteCount(); // read floating point data from file ifs.read( ptr, bytecount ); if ( ifs.fail() ) { ifs.close(); GEM_THROW( "Failed to read image data." ); } } // clean up and return ifs.close(); }
void TextureLoader::loadBMP( const std::string& _path ) { // local vars std::ifstream ifs; BITMAPFILEHEADER filehdr; BITMAPINFOHEADER infohdr; // open file for reading ifs.open( _path.c_str(), std::ifstream::in | std::ifstream::binary ); if ( ifs.fail() ) { GEM_THROW( "Could not open file " + _path ); } // read file header. // values are read one by one rather then the whole struct at once because // compilers will not always do two-padding of structs. This way is // preferred here over getting into compiler specific directives. ifs.read( reinterpret_cast<char*>(&filehdr.type), 2 ); ifs.read( reinterpret_cast<char*>(&filehdr.size), 4 ); ifs.read( reinterpret_cast<char*>(&filehdr.reserved1), 2 ); ifs.read( reinterpret_cast<char*>(&filehdr.reserved2), 2 ); ifs.read( reinterpret_cast<char*>(&filehdr.offBits), 4 ); if ( ifs.fail( ) ) { ifs.close(); GEM_THROW( "Failed to read image file header." ); } // make sure its a bitmap if ( filehdr.type == "BM" ) { ifs.close(); GEM_THROW( "File is not a bitmap." ); } // read info header ifs.read( reinterpret_cast<char*>(&infohdr), sizeof( BITMAPINFOHEADER ) ); if ( ifs.fail( ) ) { ifs.close(); GEM_THROW( "Failed to read image info header." ); } // read 24-bit (rgb) if ( infohdr.bitCount==24 ) { // allocate data createMipLevels( infohdr.width, infohdr.height, TEXTURE_FORMAT_RGB_8UI, 1 ); // get character ptr and total bytecount char* ptr = mipLevels_[0].getWritePtr<char>(); int bytecount = mipLevels_[0].getByteCount(); // jump to data section ifs.seekg( filehdr.offBits, std::ios::beg ); // read image data ifs.read( ptr, bytecount ); if ( ifs.fail() ) { ifs.close(); GEM_THROW( "Failed to read image data." ); } // data is in BGR format, so swap R and B for ( int i=0; i<bytecount; i+=3 ) { ptr[i] ^= ptr[i+2]; ptr[i+2] ^= ptr[i]; ptr[i] ^= ptr[i+2]; } } // read 8-bit (monochrome) else if ( infohdr.bitCount==8 ) { // set variables and allocate data createMipLevels( infohdr.width, infohdr.height, TEXTURE_FORMAT_R_8UI, 1 ); char* ptr = mipLevels_[0].getWritePtr<char>(); int bytecount = mipLevels_[0].getByteCount(); // jump to data section ifs.seekg( filehdr.offBits, std::ios::beg ); // read image data ifs.read( ptr, bytecount ); if ( ifs.fail() ) { ifs.close(); GEM_THROW( "Failed to read image data." ); } } // bitcount is not supported, close and report failiure else { ifs.close(); GEM_THROW( "Bitmap format not supported." ); } // close file and return ifs.close(); }
void vkImageBase::updateMipVkImage(uint64_t texSize, std::vector<void *> &pixels, std::vector<ImageInfo> &bitmapInfos, std::vector<VkBufferImageCopy> &bufferCopyRegions, VkImageViewType target, VkFormat internalFormat, int mipLevels, VkImageCreateFlags flags) { VkResult err; bool pass; VulkanRenderer *vk_renderer = static_cast<VulkanRenderer *>(Renderer::getInstance()); VkDevice device = vk_renderer->getDevice(); VkFormatProperties formatProperties; vkGetPhysicalDeviceFormatProperties(vk_renderer->getPhysicalDevice(), internalFormat, &formatProperties); VkBuffer texBuffer; VkDeviceMemory texMemory; VkMemoryAllocateInfo memoryAllocateInfo = {}; memoryAllocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; memoryAllocateInfo.pNext = NULL; memoryAllocateInfo.allocationSize = 0; memoryAllocateInfo.memoryTypeIndex = 0; err = vkCreateBuffer(device, gvr::BufferCreateInfo(texSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT), nullptr, &texBuffer); GVR_VK_CHECK(!err); // Obtain the requirements on memory for this buffer VkMemoryRequirements mem_reqs; vkGetBufferMemoryRequirements(device, texBuffer, &mem_reqs); assert(!err); memoryAllocateInfo.allocationSize = mem_reqs.size; pass = vk_renderer->GetMemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memoryAllocateInfo.memoryTypeIndex); assert(pass); size = mem_reqs.size; err = vkAllocateMemory(device, gvr::MemoryAllocateInfo(mem_reqs.size, memoryAllocateInfo.memoryTypeIndex), NULL, &texMemory); unsigned char *texData; err = vkMapMemory(device, texMemory, 0, memoryAllocateInfo.allocationSize, 0, (void **) &texData); assert(!err); int i = 0; for (auto &buffer_copy_region: bufferCopyRegions) { memcpy(texData + buffer_copy_region.bufferOffset, pixels[i], bitmapInfos[i].size); i++; } vkUnmapMemory(device, texMemory); // Bind our buffer to the memory err = vkBindBufferMemory(device, texBuffer, texMemory, 0); assert(!err); err = vkCreateImage(device, gvr::ImageCreateInfo(VK_IMAGE_TYPE_2D, internalFormat, bitmapInfos[0].width, bitmapInfos[0].height, 1, mipLevels, pixels.size(), VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, flags, getVKSampleBit(mSampleCount), VK_IMAGE_LAYOUT_UNDEFINED), NULL, &imageHandle); assert(!err); vkGetImageMemoryRequirements(device, imageHandle, &mem_reqs); memoryAllocateInfo.allocationSize = mem_reqs.size; pass = vk_renderer->GetMemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memoryAllocateInfo.memoryTypeIndex); assert(pass); /* allocate memory */ err = vkAllocateMemory(device, &memoryAllocateInfo, NULL, &device_memory); assert(!err); /* bind memory */ err = vkBindImageMemory(device, imageHandle, device_memory, 0); assert(!err); // Reset the setup command buffer VkCommandBuffer textureCmdBuffer; vk_renderer->initCmdBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, textureCmdBuffer); vkResetCommandBuffer(textureCmdBuffer, 0); VkCommandBufferInheritanceInfo commandBufferInheritanceInfo = {}; commandBufferInheritanceInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO; commandBufferInheritanceInfo.pNext = NULL; commandBufferInheritanceInfo.renderPass = VK_NULL_HANDLE; commandBufferInheritanceInfo.subpass = 0; commandBufferInheritanceInfo.framebuffer = VK_NULL_HANDLE; commandBufferInheritanceInfo.occlusionQueryEnable = VK_FALSE; commandBufferInheritanceInfo.queryFlags = 0; commandBufferInheritanceInfo.pipelineStatistics = 0; VkCommandBufferBeginInfo setupCmdsBeginInfo; setupCmdsBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; setupCmdsBeginInfo.pNext = NULL; setupCmdsBeginInfo.flags = 0; setupCmdsBeginInfo.pInheritanceInfo = &commandBufferInheritanceInfo; // Begin recording to the command buffer. vkBeginCommandBuffer(textureCmdBuffer, &setupCmdsBeginInfo); VkImageMemoryBarrier imageMemoryBarrier = {}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.pNext = NULL; imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.baseMipLevel = 0; imageMemoryBarrier.subresourceRange.levelCount = 1; imageMemoryBarrier.subresourceRange.baseArrayLayer = 0; imageMemoryBarrier.subresourceRange.layerCount = pixels.size(); imageMemoryBarrier.srcAccessMask = 0; imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; // Optimal image will be used as destination for the copy, so we must transfer from our initial undefined image layout to the transfer destination layout setImageLayout(imageMemoryBarrier, textureCmdBuffer, imageHandle, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageMemoryBarrier.subresourceRange); vkCmdCopyBufferToImage( textureCmdBuffer, texBuffer, imageHandle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, static_cast<uint32_t>(bufferCopyRegions.size()), bufferCopyRegions.data()); imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; setImageLayout(imageMemoryBarrier, textureCmdBuffer, imageHandle, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageMemoryBarrier.subresourceRange); // We are finished recording operations. vkEndCommandBuffer(textureCmdBuffer); VkCommandBuffer buffers[1]; buffers[0] = textureCmdBuffer; VkSubmitInfo submit_info; submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submit_info.pNext = NULL; submit_info.waitSemaphoreCount = 0; submit_info.pWaitSemaphores = NULL; submit_info.pWaitDstStageMask = NULL; submit_info.commandBufferCount = 1; submit_info.pCommandBuffers = &buffers[0]; submit_info.signalSemaphoreCount = 0; submit_info.pSignalSemaphores = NULL; VkQueue queue = vk_renderer->getQueue(); // Submit to our shared graphics queue. err = vkQueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); assert(!err); // Wait for the queue to become idle. err = vkQueueWaitIdle(queue); assert(!err); vkFreeMemory(device, texMemory, nullptr); vkDestroyBuffer(device, texBuffer, nullptr); if(mipLevels > 1) createMipLevels(formatProperties, vk_renderer, setupCmdsBeginInfo, bufferCopyRegions, mipLevels, bitmapInfos, imageMemoryBarrier, submit_info, buffers, queue); err = vkCreateImageView(device, gvr::ImageViewCreateInfo(imageHandle, target, internalFormat, mipLevels,0, pixels.size(), VK_IMAGE_ASPECT_COLOR_BIT), NULL, &imageView); assert(!err); }