mirror of
https://github.com/Kbz-8/Pulse.git
synced 2026-01-10 15:03:34 +00:00
207 lines
7.1 KiB
C
207 lines
7.1 KiB
C
// Copyright (C) 2025 kbz_8
|
|
// This file is part of "Pulse"
|
|
// For conditions of distribution and use, see copyright notice in LICENSE
|
|
|
|
#include "Pulse.h"
|
|
#include "PulseDefs.h"
|
|
#include "PulseInternal.h"
|
|
|
|
PULSE_API PulseImage PulseCreateImage(PulseDevice device, const PulseImageCreateInfo* create_infos)
|
|
{
|
|
PULSE_CHECK_HANDLE_RETVAL(device, PULSE_NULL_HANDLE);
|
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend))
|
|
{
|
|
if(create_infos == PULSE_NULLPTR)
|
|
{
|
|
PulseLogError(device->backend, "create_infos is NULL");
|
|
PulseSetInternalError(PULSE_ERROR_INITIALIZATION_FAILED);
|
|
return PULSE_NULL_HANDLE;
|
|
}
|
|
|
|
bool failed = false;
|
|
const uint32_t MAX_2D_DIMENSION = 16384;
|
|
const uint32_t MAX_3D_DIMENSION = 2048;
|
|
|
|
if(create_infos->width <= 0 || create_infos->height <= 0 || create_infos->layer_count_or_depth <= 0)
|
|
{
|
|
PulseLogError(device->backend, "any image: width, height, and layer_count_or_depth must be >= 1");
|
|
failed = true;
|
|
}
|
|
|
|
if(create_infos->type == PULSE_IMAGE_TYPE_CUBE)
|
|
{
|
|
if(create_infos->width != create_infos->height)
|
|
{
|
|
PulseLogError(device->backend, "cube images: width and height must be identical");
|
|
failed = true;
|
|
}
|
|
if(create_infos->width > MAX_2D_DIMENSION || create_infos->height > MAX_2D_DIMENSION)
|
|
{
|
|
PulseLogError(device->backend, "cube images: width and height must be <= 16384");
|
|
failed = true;
|
|
}
|
|
if(create_infos->layer_count_or_depth != 6)
|
|
{
|
|
PulseLogError(device->backend, "cube images: layer_count_or_depth must be 6");
|
|
failed = true;
|
|
}
|
|
if(!PulseIsImageFormatValid(device, create_infos->format, PULSE_IMAGE_TYPE_CUBE, create_infos->usage))
|
|
{
|
|
PulseLogError(device->backend, "cube images: the format is unsupported for the given usage");
|
|
failed = true;
|
|
}
|
|
}
|
|
else if(create_infos->type == PULSE_IMAGE_TYPE_CUBE_ARRAY)
|
|
{
|
|
if(create_infos->width != create_infos->height)
|
|
{
|
|
PulseLogError(device->backend, "cube array images: width and height must be identical");
|
|
failed = true;
|
|
}
|
|
if(create_infos->width > MAX_2D_DIMENSION || create_infos->height > MAX_2D_DIMENSION)
|
|
{
|
|
PulseLogError(device->backend, "cube array images: width and height must be <= 16384");
|
|
failed = true;
|
|
}
|
|
if(create_infos->layer_count_or_depth % 6 != 0)
|
|
{
|
|
PulseLogError(device->backend, "cube array images: layer_count_or_depth must be a multiple of 6");
|
|
failed = true;
|
|
}
|
|
if(!PulseIsImageFormatValid(device, create_infos->format, PULSE_IMAGE_TYPE_CUBE_ARRAY, create_infos->usage))
|
|
{
|
|
PulseLogError(device->backend, "cube array images: the format is unsupported for the given usage");
|
|
failed = true;
|
|
}
|
|
}
|
|
else if(create_infos->type == PULSE_IMAGE_TYPE_3D)
|
|
{
|
|
if(create_infos->width > MAX_3D_DIMENSION || create_infos->height > MAX_3D_DIMENSION || create_infos->layer_count_or_depth > MAX_3D_DIMENSION)
|
|
{
|
|
PulseLogError(device->backend, "3D images: width, height, and layer_count_or_depth must be <= 2048");
|
|
failed = true;
|
|
}
|
|
if(!PulseIsImageFormatValid(device, create_infos->format, PULSE_IMAGE_TYPE_3D, create_infos->usage))
|
|
{
|
|
PulseLogError(device->backend, "3D images: the format is unsupported for the given usage");
|
|
failed = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(create_infos->width > MAX_2D_DIMENSION || create_infos->height > MAX_2D_DIMENSION)
|
|
{
|
|
PulseLogError(device->backend, "2D images: width and height must be <= 16384");
|
|
failed = true;
|
|
}
|
|
if(!PulseIsImageFormatValid(device, create_infos->format, PULSE_IMAGE_TYPE_2D, create_infos->usage))
|
|
{
|
|
PulseLogError(device->backend, "2D images: the format is unsupported for the given usage");
|
|
failed = true;
|
|
}
|
|
}
|
|
|
|
if(failed)
|
|
return PULSE_NULL_HANDLE;
|
|
}
|
|
PulseImage image = device->PFN_CreateImage(device, create_infos);
|
|
if(image == PULSE_NULL_HANDLE)
|
|
return PULSE_NULL_HANDLE;
|
|
|
|
image->device = device;
|
|
image->type = create_infos->type;
|
|
image->format = create_infos->format;
|
|
image->usage = create_infos->usage;
|
|
image->width = create_infos->width;
|
|
image->height = create_infos->height;
|
|
image->layer_count_or_depth = create_infos->layer_count_or_depth;
|
|
|
|
PULSE_EXPAND_ARRAY_IF_NEEDED(device->allocated_images, PulseImage, device->allocated_images_size, device->allocated_images_capacity, 64);
|
|
device->allocated_images[device->allocated_images_size] = image;
|
|
device->allocated_images_size++;
|
|
return image;
|
|
}
|
|
|
|
PULSE_API bool PulseIsImageFormatValid(PulseDevice device, PulseImageFormat format, PulseImageType type, PulseImageUsageFlags usage)
|
|
{
|
|
PULSE_CHECK_HANDLE_RETVAL(device, false);
|
|
return device->PFN_IsImageFormatValid(device, format, type, usage);
|
|
}
|
|
|
|
PULSE_API bool PulseCopyImageToBuffer(PulseCommandList cmd, const PulseImageRegion* src, const PulseBufferRegion* dst)
|
|
{
|
|
PULSE_CHECK_PTR_RETVAL(src, false);
|
|
PULSE_CHECK_HANDLE_RETVAL(src->image, false);
|
|
PULSE_CHECK_PTR_RETVAL(dst, false);
|
|
PULSE_CHECK_HANDLE_RETVAL(dst->buffer, false);
|
|
|
|
PulseBackend backend = src->image->device->backend;
|
|
|
|
if(src->image->device != dst->buffer->device)
|
|
{
|
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend))
|
|
PulseLogErrorFmt(backend, "source image has been created on a different device (%p) than the destination buffer (%p)", src->image->device, dst->buffer->device);
|
|
PulseSetInternalError(PULSE_ERROR_INVALID_DEVICE);
|
|
return false;
|
|
}
|
|
|
|
if(dst->size + dst->offset > dst->buffer->size)
|
|
{
|
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend))
|
|
PulseLogErrorFmt(backend, "destination buffer region (%lld) is bigger than the buffer size (%lld)", dst->size + dst->offset, dst->buffer->size);
|
|
PulseSetInternalError(PULSE_ERROR_INVALID_REGION);
|
|
return false;
|
|
}
|
|
|
|
if(src->width > src->image->width)
|
|
{
|
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend))
|
|
PulseLogErrorFmt(backend, "source image region width (%lld) is bigger than image width (%lld)", src->width, src->image->width);
|
|
PulseSetInternalError(PULSE_ERROR_INVALID_REGION);
|
|
return false;
|
|
}
|
|
|
|
if(src->height > src->image->height)
|
|
{
|
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(backend))
|
|
PulseLogErrorFmt(backend, "source image region height (%lld) is bigger than image height (%lld)", src->height, src->image->height);
|
|
PulseSetInternalError(PULSE_ERROR_INVALID_REGION);
|
|
return false;
|
|
}
|
|
|
|
return src->image->device->PFN_CopyImageToBuffer(cmd, src, dst);
|
|
}
|
|
|
|
PULSE_API bool PulseBlitImage(PulseCommandList cmd, const PulseImageRegion* src, const PulseImageRegion* dst)
|
|
{
|
|
}
|
|
|
|
PULSE_API void PulseDestroyImage(PulseDevice device, PulseImage image)
|
|
{
|
|
PULSE_CHECK_HANDLE(device);
|
|
|
|
if(image == PULSE_NULL_HANDLE)
|
|
{
|
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend))
|
|
PulseLogWarning(device->backend, "image is NULL, this may be a bug in your application");
|
|
return;
|
|
}
|
|
if(image->device != device)
|
|
{
|
|
if(PULSE_IS_BACKEND_LOW_LEVEL_DEBUG(device->backend))
|
|
PulseLogErrorFmt(device->backend, "cannot destroy image [%p] that have been allocated with device [%p] using device [%p]", image, image->device, device);
|
|
PulseSetInternalError(PULSE_ERROR_INVALID_DEVICE);
|
|
return;
|
|
}
|
|
for(uint32_t i = 0; i < device->allocated_images_size; i++)
|
|
{
|
|
if(device->allocated_images[i] == image)
|
|
{
|
|
PULSE_DEFRAG_ARRAY(device->allocated_images, device->allocated_images_size, i);
|
|
break;
|
|
}
|
|
}
|
|
device->PFN_DestroyImage(device, image);
|
|
device->allocated_images_size--;
|
|
}
|