Skip to content

Commit

Permalink
Extend the image class to allow uploading custom mipmaps
Browse files Browse the repository at this point in the history
  • Loading branch information
ApoorvaJ committed Sep 18, 2023
1 parent 3013728 commit 266385c
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 41 deletions.
20 changes: 18 additions & 2 deletions source/MaterialXRender/Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,12 @@ UnsignedIntPair getMaxDimensions(const vector<ImagePtr>& imageVec)
// Image methods
//

Image::Image(unsigned int width, unsigned int height, unsigned int channelCount, BaseType baseType) :
Image::Image(unsigned int width, unsigned int height, unsigned int channelCount, BaseType baseType, bool useCustomMipMaps) :
_width(width),
_height(height),
_channelCount(channelCount),
_baseType(baseType),
_useCustomMipMaps(useCustomMipMaps),
_resourceBuffer(nullptr),
_resourceBufferDeallocator(nullptr),
_resourceId(0)
Expand Down Expand Up @@ -505,7 +506,22 @@ void Image::writeTable(const FilePath& filePath, unsigned int channel)
void Image::createResourceBuffer()
{
releaseResourceBuffer();
_resourceBuffer = malloc(_width * _height * _channelCount * getBaseStride());
size_t numTexels = 0;
if (_useCustomMipMaps)
{
int w = _width;
int h = _height;
while (w > 0 && h > 0) {
numTexels += w * h;
w /= 2;
h /= 2;
}
}
else
{
numTexels = _width * _height;
}
_resourceBuffer = malloc(numTexels * _channelCount * getBaseStride());
_resourceBufferDeallocator = nullptr;
}

Expand Down
18 changes: 15 additions & 3 deletions source/MaterialXRender/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,15 @@ class MX_RENDER_API Image

public:
/// Create an empty image with the given properties.
static ImagePtr create(unsigned int width, unsigned int height, unsigned int channelCount, BaseType baseType = BaseType::UINT8)
static ImagePtr create(
unsigned int width,
unsigned int height,
unsigned int channelCount,
BaseType baseType = BaseType::UINT8,
bool useCustomMipMaps = false
)
{
return ImagePtr(new Image(width, height, channelCount, baseType));
return ImagePtr(new Image(width, height, channelCount, baseType, useCustomMipMaps));
}

~Image();
Expand Down Expand Up @@ -89,6 +95,11 @@ class MX_RENDER_API Image
return _baseType;
}

bool getUseCustomMipMaps() const
{
return _useCustomMipMaps;
}

/// Return the stride of our base type in bytes.
unsigned int getBaseStride() const;

Expand Down Expand Up @@ -207,13 +218,14 @@ class MX_RENDER_API Image
/// @}

protected:
Image(unsigned int width, unsigned int height, unsigned int channelCount, BaseType baseType);
Image(unsigned int width, unsigned int height, unsigned int channelCount, BaseType baseType, bool useCustomMipMaps);

protected:
unsigned int _width;
unsigned int _height;
unsigned int _channelCount;
BaseType _baseType;
bool _useCustomMipMaps;

void* _resourceBuffer;
ImageBufferDeallocator _resourceBufferDeallocator;
Expand Down
74 changes: 49 additions & 25 deletions source/MaterialXRenderMsl/MetalTextureHandler.mm
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@
(!generateMipMaps ? MTLTextureUsageRenderTarget : 0);
texDesc.resourceOptions = MTLResourceStorageModePrivate;
texDesc.pixelFormat = pixelFormat;
if(generateMipMaps)
if(generateMipMaps && !image->getUseCustomMipMaps())
{
if(image->getChannelCount() == 1)
{
Expand Down Expand Up @@ -193,30 +193,40 @@

NSUInteger channelCount = image->getChannelCount();

NSUInteger sourceBytesPerRow =
image->getWidth() *
channelCount *
getTextureBaseTypeSize(image->getBaseType());
NSUInteger sourceBytesPerImage =
sourceBytesPerRow *
image->getHeight();
int numBytesPerTexel = channelCount * getTextureBaseTypeSize(image->getBaseType());
int numUploadMips = image->getUseCustomMipMaps() ? image->getMaxMipCount() : 1;
size_t numTexelsAcrossMips = 0;
if (image->getUseCustomMipMaps())
{
int w = image->getWidth();
int h = image->getHeight();
while (w > 0 && h > 0) {
numTexelsAcrossMips += w * h;
w /= 2;
h /= 2;
}
}
else
{
numTexelsAcrossMips = image->getWidth() * image->getHeight();
}

std::vector<float> rearrangedDataF;
std::vector<unsigned char> rearrangedDataC;
void* imageData = image->getResourceBuffer();


if ((pixelFormat == MTLPixelFormatRGBA32Float || pixelFormat == MTLPixelFormatRGBA8Unorm) && channelCount == 3)
{
bool isFloat = pixelFormat == MTLPixelFormatRGBA32Float;

sourceBytesPerRow = sourceBytesPerRow / 3 * 4;
sourceBytesPerImage = sourceBytesPerImage / 3 * 4;
numBytesPerTexel = numBytesPerTexel / 3 * 4;

size_t srcIdx = 0;

if(isFloat)
{
rearrangedDataF.resize(sourceBytesPerImage / sizeof(float));
rearrangedDataF.resize(numTexelsAcrossMips * numBytesPerTexel / sizeof(float));
for(size_t dstIdx = 0; dstIdx < rearrangedDataF.size(); ++dstIdx)
{
if((dstIdx & 0x3) == 3)
Expand All @@ -232,7 +242,7 @@
}
else
{
rearrangedDataC.resize(sourceBytesPerImage);
rearrangedDataC.resize(numTexelsAcrossMips * numBytesPerTexel);
for(size_t dstIdx = 0; dstIdx < rearrangedDataC.size(); ++dstIdx)
{
if((dstIdx & 0x3) == 3)
Expand All @@ -253,22 +263,36 @@
id<MTLBuffer> buffer = nil;
if(imageData)
{
buffer = [_device newBufferWithBytes:imageData
length:sourceBytesPerImage
options:MTLStorageModeShared];
[blitCmdEncoder copyFromBuffer:buffer sourceOffset:0
sourceBytesPerRow:sourceBytesPerRow
sourceBytesPerImage:sourceBytesPerImage
sourceSize:MTLSizeMake(image->getWidth(), image->getHeight(), 1)
toTexture:texture
destinationSlice:0
destinationLevel:0
destinationOrigin:MTLOriginMake(0, 0, 0)];
buffer = [_device
newBufferWithBytes:imageData
length:(numTexelsAcrossMips * numBytesPerTexel)
options:MTLStorageModeShared];
int width = image->getWidth();
int height = image->getHeight();
int sourceOffset = 0;
for (int mipLevel = 0; mipLevel < numUploadMips; mipLevel++)
{
NSUInteger sourceBytesPerRow = width * numBytesPerTexel;
NSUInteger sourceBytesPerImage = height * sourceBytesPerRow;
[blitCmdEncoder
copyFromBuffer:buffer
sourceOffset:sourceOffset
sourceBytesPerRow:sourceBytesPerRow
sourceBytesPerImage:sourceBytesPerImage
sourceSize:MTLSizeMake(width, height, 1)
toTexture:texture
destinationSlice:0
destinationLevel:mipLevel
destinationOrigin:MTLOriginMake(0, 0, 0)];
sourceOffset += width * height * numBytesPerTexel;
width = width / 2;
height = height / 2;
}
}

if(generateMipMaps && image->getMaxMipCount() > 1)
if(generateMipMaps && !image->getUseCustomMipMaps() && image->getMaxMipCount() > 1)
[blitCmdEncoder generateMipmapsForTexture:texture];

[blitCmdEncoder endEncoding];

[cmdBuffer commit];
Expand Down
76 changes: 65 additions & 11 deletions source/MaterialXView/Viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,12 +445,68 @@ void Viewer::initialize()
void Viewer::loadEnvironmentLight()
{
// Load the requested radiance map.
mx::ImagePtr envRadianceMap = _imageHandler->acquireImage(_envRadianceFilename);
if (!envRadianceMap)
{
new ng::MessageDialog(this, ng::MessageDialog::Type::Warning, "Failed to load environment light");
return;
// mx::ImagePtr envRadianceMap = _imageHandler->acquireImage(_envRadianceFilename);
// if (!envRadianceMap)
// {
// new ng::MessageDialog(this, ng::MessageDialog::Type::Warning, "Failed to load environment light");
// return;
// }
mx::ImagePtr envRadianceMap = mx::Image::create(1024, 1024, 4, mx::Image::BaseType::UINT8, true);
envRadianceMap->createResourceBuffer();
{
int numMips = envRadianceMap->getMaxMipCount();
int w = envRadianceMap->getWidth();
int h = envRadianceMap->getHeight();
char* writePtr = (char*)envRadianceMap->getResourceBuffer();
for (int i = 0; i < numMips; i++)
{
uint8_t color[4] = { 0, 0, 0, 255};
switch (i)
{
case 0:
color[0] = 255;
break;
case 1:
color[1] = 255;
break;
case 2:
color[2] = 255;
break;
case 3:
color[0] = 255;
color[1] = 255;
break;
case 4:
color[0] = 255;
color[2] = 255;
break;
case 5:
color[1] = 255;
color[2] = 255;
break;
case 6:
color[0] = 255;
color[1] = 255;
color[2] = 255;
break;
}

for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
writePtr[0] = color[0];
writePtr[1] = color[1];
writePtr[2] = color[2];
writePtr[3] = color[3];
writePtr += 4;
}
}
w = w/2;
h = h/2;
}
}
// envRadianceMap->setUniformColor(mx::Color4(0.0f, 1.0f, 0.0f, 1.0f));

// If requested, normalize the environment upon loading.
if (_normalizeEnvironment)
Expand Down Expand Up @@ -837,12 +893,10 @@ void Viewer::createAdvancedSettings(Widget* parent)
lightingLabel->set_font_size(20);
lightingLabel->set_font("sans-bold");

ng::CheckBox* directLightingBox = new ng::CheckBox(advancedPopup, "Direct Lighting");
directLightingBox->set_checked(_lightHandler->getDirectLighting());
directLightingBox->set_callback([this](bool enable)
{
_lightHandler->setDirectLighting(enable);
});
// ---------
// Don't commit this
_lightHandler->setDirectLighting(false);
// ---------

ng::CheckBox* indirectLightingBox = new ng::CheckBox(advancedPopup, "Indirect Lighting");
indirectLightingBox->set_checked(_lightHandler->getIndirectLighting());
Expand Down

0 comments on commit 266385c

Please sign in to comment.