Files
gtk/gsk/gskslvalue.c
Benjamin Otte d33881e0ec gsksltype: Implement arrays
This is incomplete as we can only declare variables using array types
but not as arrays of static types yet.
2017-10-30 02:58:03 +01:00

349 lines
9.4 KiB
C

/* GTK - The GIMP Toolkit
*
* Copyright © 2017 Benjamin Otte <otte@gnome.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gskslvalueprivate.h"
#include "gskslprinterprivate.h"
#include "gsksltypeprivate.h"
#include "gskspvwriterprivate.h"
struct _GskSlValue {
GskSlType *type;
gpointer data;
GDestroyNotify free_func;
gpointer user_data;
};
GskSlValue *
gsk_sl_value_new (GskSlType *type)
{
gpointer data;
g_return_val_if_fail (gsk_sl_type_get_size (type) > 0, NULL);
data = g_malloc0 (gsk_sl_type_get_size (type));
return gsk_sl_value_new_for_data (type, data, g_free, data);
}
GskSlValue *
gsk_sl_value_new_for_data (GskSlType *type,
gpointer data,
GDestroyNotify free_func,
gpointer user_data)
{
GskSlValue *value;
g_return_val_if_fail (gsk_sl_type_get_size (type) > 0, NULL);
g_return_val_if_fail (data != NULL, NULL);
value = g_slice_new0 (GskSlValue);
value->type = gsk_sl_type_ref (type);
value->data = data;
value->free_func = free_func;
value->user_data = user_data;
return value;
}
/**
* gsk_sl_value_new_convert:
* @source: value to convert
* @new_type: type to convert to
*
* Converts @source into the @new_type. This function uses the extended
* conversion rules for constructors. If you want to restrict yourself
* to the usual conversion rules, call this function after checking
* for compatibility via gsk_sl_type_can_convert().
*
* Returns: a new value containing the converted @source or %NULL
* if the source cannot be converted to @type.
**/
GskSlValue *
gsk_sl_value_new_convert (GskSlValue *source,
GskSlType *new_type)
{
GskSlValue *result;
if (gsk_sl_type_equal (source->type, new_type))
{
return gsk_sl_value_copy (source);
}
else if (gsk_sl_type_is_scalar (source->type))
{
if (!gsk_sl_type_is_scalar (new_type))
return NULL;
result = gsk_sl_value_new (new_type);
gsk_sl_scalar_type_convert_value (gsk_sl_type_get_scalar_type (new_type),
result->data,
gsk_sl_type_get_scalar_type (source->type),
source->data);
return result;
}
else if (gsk_sl_type_is_vector (source->type))
{
guchar *sdata, *ddata;
gsize sstride, dstride;
guint i, n;
if (!gsk_sl_type_is_vector (new_type) ||
gsk_sl_type_get_length (new_type) != gsk_sl_type_get_length (source->type))
return NULL;
n = gsk_sl_type_get_length (new_type);
result = gsk_sl_value_new (new_type);
sdata = source->data;
ddata = result->data;
sstride = gsk_sl_type_get_index_stride (source->type);
dstride = gsk_sl_type_get_index_stride (new_type);
for (i = 0; i < n; i++)
{
gsk_sl_scalar_type_convert_value (gsk_sl_type_get_scalar_type (new_type),
ddata + i * dstride,
gsk_sl_type_get_scalar_type (source->type),
sdata + i * sstride);
}
return result;
}
else if (gsk_sl_type_is_matrix (source->type))
{
guchar *sdata, *ddata;
gsize sstride, dstride;
guint i, n;
if (!gsk_sl_type_is_matrix (new_type) ||
gsk_sl_type_get_length (new_type) != gsk_sl_type_get_length (source->type) ||
gsk_sl_type_get_length (gsk_sl_type_get_index_type (new_type)) != gsk_sl_type_get_length (gsk_sl_type_get_index_type (source->type)))
return NULL;
n = gsk_sl_type_get_length (new_type) * gsk_sl_type_get_length (gsk_sl_type_get_index_type (source->type));
result = gsk_sl_value_new (new_type);
sdata = source->data;
ddata = result->data;
sstride = gsk_sl_type_get_size (source->type) / n;
dstride = gsk_sl_type_get_size (new_type) / n;
for (i = 0; i < n; i++)
{
gsk_sl_scalar_type_convert_value (gsk_sl_type_get_scalar_type (new_type),
ddata + i * dstride,
gsk_sl_type_get_scalar_type (source->type),
sdata + i * sstride);
}
return result;
}
else
{
return NULL;
}
}
GskSlValue *
gsk_sl_value_new_index (GskSlValue *value,
gsize n)
{
GskSlType *index_type;
gpointer data;
if (n >= gsk_sl_type_get_length (value->type))
return NULL;
index_type = gsk_sl_type_get_index_type (value->type);
data = g_memdup ((guchar *) value->data + gsk_sl_type_get_index_stride (value->type) * n,
gsk_sl_type_get_size (index_type));
return gsk_sl_value_new_for_data (index_type, data, g_free, data);
}
GskSlValue *
gsk_sl_value_new_member (GskSlValue *value,
guint n)
{
GskSlType *member_type;
gpointer data;
member_type = gsk_sl_type_get_member_type (value->type, n);
data = g_memdup ((guchar *) value->data + gsk_sl_type_get_member_offset (value->type, n),
gsk_sl_type_get_size (member_type));
return gsk_sl_value_new_for_data (member_type, data, g_free, data);
}
/**
* gsk_sl_value_convert_components:
* @source: (transfer full): value to convert
* @scalar: new scalar type to convert to
*
* Converts the scalar components of @source into the @scalar.
* This function uses the extended conversion rules for constructors.
*
* Returns: A value containing the converted values. This may or may not
* be the original @source.
**/
GskSlValue *
gsk_sl_value_convert_components (GskSlValue *source,
GskSlScalarType scalar)
{
GskSlValue *result;
GskSlType *result_type;
guchar *sdata, *ddata;
gsize sstride, dstride;
gsize i, n;
GskSlScalarType sscalar;
sscalar = gsk_sl_type_get_scalar_type (source->type);
if (sscalar == scalar)
return source;
result_type = gsk_sl_type_get_matching (source->type, scalar);
result = gsk_sl_value_new (result_type);
n = gsk_sl_type_get_n_components (result_type);
sdata = gsk_sl_value_get_data (source);
sstride = gsk_sl_scalar_type_get_size (sscalar);
ddata = gsk_sl_value_get_data (result);
dstride = gsk_sl_scalar_type_get_size (scalar);
for (i = 0; i < n; i++)
{
gsk_sl_scalar_type_convert_value (scalar,
ddata + i * dstride,
sscalar,
sdata + i * sstride);
}
gsk_sl_value_free (source);
return result;
}
GskSlValue *
gsk_sl_value_copy (const GskSlValue *source)
{
gpointer data;
data = g_memdup (source->data, gsk_sl_type_get_size (source->type));
return gsk_sl_value_new_for_data (source->type, data, g_free, data);
}
void
gsk_sl_value_free (GskSlValue *value)
{
if (value == NULL)
return;
if (value->free_func)
value->free_func (value->user_data);
gsk_sl_type_unref (value->type);
g_slice_free (GskSlValue, value);
}
void
gsk_sl_value_componentwise (GskSlValue *value,
void (* func) (gpointer, gpointer),
gpointer user_data)
{
gsize stride;
gsize i, n;
g_return_if_fail (gsk_sl_type_get_n_components (value->type) > 0);
stride = gsk_sl_scalar_type_get_size (gsk_sl_type_get_scalar_type (value->type));
n = gsk_sl_type_get_n_components (value->type);
for (i = 0; i < n; i++)
{
func ((guchar *) value->data + stride * i, user_data);
}
}
void
gsk_sl_value_print (const GskSlValue *value,
GskSlPrinter *printer)
{
gsk_sl_type_print_value (value->type, printer, value->data);
}
char *
gsk_sl_value_to_string (const GskSlValue *value)
{
GskSlPrinter *printer;
char *s;
printer = gsk_sl_printer_new ();
gsk_sl_value_print (value, printer);
s = gsk_sl_printer_write_to_string (printer);
gsk_sl_printer_unref (printer);
return s;
}
GskSlType *
gsk_sl_value_get_type (const GskSlValue *value)
{
return value->type;
}
gpointer
gsk_sl_value_get_data (const GskSlValue *value)
{
return value->data;
}
gboolean
gsk_sl_value_equal (gconstpointer a_,
gconstpointer b_)
{
const GskSlValue *a = a_;
const GskSlValue *b = b_;
if (!gsk_sl_type_equal (a->type, b->type))
return FALSE;
return gsk_sl_type_value_equal (a->type, a->data, b->data);
}
guint
gsk_sl_value_hash (gconstpointer value_)
{
const GskSlValue *value = value_;
/* XXX: We definitely want to hash the data here ! */
return gsk_sl_type_hash (value->type);
}
guint32
gsk_sl_value_write_spv (const GskSlValue *value,
GskSpvWriter *writer)
{
return gsk_sl_type_write_value_spv (value->type, writer, value->data);
}