static cg_texture_t * make_texture (void) { void *tex_data; uint32_t *p; cg_texture_t *tex; int partx, party, width, height; p = tex_data = c_malloc (TEXTURE_SIZE * TEXTURE_SIZE * 4); /* Make a texture with a different color for each part */ for (party = 0; party < PARTS; party++) { height = (party < PARTS - 1 ? PART_SIZE : TEXTURE_SIZE - PART_SIZE * (PARTS - 1)); for (partx = 0; partx < PARTS; partx++) { uint32_t color = corner_colors[party * PARTS + partx]; width = (partx < PARTS - 1 ? PART_SIZE : TEXTURE_SIZE - PART_SIZE * (PARTS - 1)); while (width-- > 0) *(p++) = C_UINT32_TO_BE (color); } while (--height > 0) { memcpy (p, p - TEXTURE_SIZE, TEXTURE_SIZE * 4); p += TEXTURE_SIZE; } } tex = test_cg_texture_new_from_data (test_dev, TEXTURE_SIZE, TEXTURE_SIZE, TEST_CG_TEXTURE_NO_ATLAS, CG_PIXEL_FORMAT_RGBA_8888_PRE, TEXTURE_SIZE * 4, tex_data); c_free (tex_data); if (test_verbose ()) { if (cg_texture_is_sliced (tex)) c_print ("Texture is sliced\n"); else c_print ("Texture is not sliced\n"); } /* The texture should be sliced unless NPOTs are supported */ c_assert (cg_has_feature (test_dev, CG_FEATURE_ID_TEXTURE_NPOT) ? !cg_texture_is_sliced (tex) : cg_texture_is_sliced (tex)); return tex; }
static int get_max_activateable_texture_units(cg_device_t *dev) { if (C_UNLIKELY(dev->max_activateable_texture_units == -1)) { GLint values[3]; int n_values = 0; int i; #ifdef CG_HAS_GL_SUPPORT if (!_cg_has_private_feature(dev, CG_PRIVATE_FEATURE_GL_EMBEDDED)) { /* GL_MAX_TEXTURE_COORDS is provided for GLSL. It defines * the number of texture coordinates that can be uploaded * (but doesn't necessarily relate to how many texture * images can be sampled) */ if (cg_has_feature(dev, CG_FEATURE_ID_GLSL)) { /* Previously this code subtracted the value by one but there was no explanation for why it did this and it doesn't seem to make sense so it has been removed */ GE(dev, glGetIntegerv(GL_MAX_TEXTURE_COORDS, values + n_values++)); /* GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS is defined for GLSL */ GE(dev, glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, values + n_values++)); } } #endif /* CG_HAS_GL_SUPPORT */ #ifdef CG_HAS_GLES2_SUPPORT if (_cg_has_private_feature(dev, CG_PRIVATE_FEATURE_GL_EMBEDDED)) { GE(dev, glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, values + n_values)); /* Two of the vertex attribs need to be used for the position and color */ values[n_values++] -= 2; GE(dev, glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, values + n_values++)); } #endif c_assert(n_values <= C_N_ELEMENTS(values) && n_values > 0); /* Use the maximum value */ dev->max_activateable_texture_units = values[0]; for (i = 1; i < n_values; i++) dev->max_activateable_texture_units = MAX(values[i], dev->max_activateable_texture_units); } return dev->max_activateable_texture_units; }
/* OpenGL - unlike GLES - can upload a sub region of pixel data from a larger * source buffer */ static void prep_gl_for_pixels_upload_full(cg_device_t *dev, int pixels_rowstride, int image_height, int pixels_src_x, int pixels_src_y, int pixels_bpp) { GE(dev, glPixelStorei(GL_UNPACK_ROW_LENGTH, pixels_rowstride / pixels_bpp)); GE(dev, glPixelStorei(GL_UNPACK_SKIP_PIXELS, pixels_src_x)); GE(dev, glPixelStorei(GL_UNPACK_SKIP_ROWS, pixels_src_y)); if (cg_has_feature(dev, CG_FEATURE_ID_TEXTURE_3D)) GE(dev, glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, image_height)); _cg_texture_gl_prep_alignment_for_pixels_upload(dev, pixels_rowstride); }
bool _cg_texture_2d_gl_can_create(cg_device_t *dev, int width, int height, cg_pixel_format_t internal_format) { GLenum gl_intformat; GLenum gl_format; GLenum gl_type; #if defined(C_PLATFORM_WEB) /* XXX: Although webgl has limited supported from NOP textures, this * is a hack to help find places to try and convert over to using * NPOT textures... */ if (!(_cg_util_is_pot(width) && _cg_util_is_pot(height))) { c_warning("WARNING: NPOT texture: width=%d height=%d", width, height); _c_web_console_trace(); } #endif /* If NPOT textures aren't supported then the size must be a power of two */ if (!cg_has_feature(dev, CG_FEATURE_ID_TEXTURE_NPOT_BASIC) && (!_cg_util_is_pot(width) || !_cg_util_is_pot(height))) return false; dev->driver_vtable->pixel_format_to_gl(dev, internal_format, &gl_intformat, &gl_format, &gl_type); /* Check that the driver can create a texture with that size */ if (!dev->texture_driver->size_supported(dev, GL_TEXTURE_2D, gl_intformat, gl_format, gl_type, width, height)) return false; return true; }
void test_npot_texture (void) { if (test_verbose ()) { if (cg_has_feature (test_dev, CG_FEATURE_ID_TEXTURE_NPOT)) c_print ("NPOT textures are supported\n"); else c_print ("NPOT textures are not supported\n"); } cg_framebuffer_orthographic (test_fb, 0, 0, cg_framebuffer_get_width (test_fb), cg_framebuffer_get_height (test_fb), -1, 100); paint (); validate_result (); if (test_verbose ()) c_print ("OK\n"); }
static bool setup_spans(cg_device_t *dev, cg_texture_2d_sliced_t *tex_2ds, int width, int height, int max_waste, cg_pixel_format_t internal_format, cg_error_t **error) { int max_width; int max_height; int n_x_slices; int n_y_slices; int (*slices_for_size)(int, int, int, c_array_t *); /* Initialize size of largest slice according to supported features */ if (cg_has_feature(dev, CG_FEATURE_ID_TEXTURE_NPOT)) { max_width = width; max_height = height; slices_for_size = _cg_rect_slices_for_size; } else { max_width = _cg_util_next_p2(width); max_height = _cg_util_next_p2(height); slices_for_size = _cg_pot_slices_for_size; } /* Negative number means no slicing forced by the user */ if (max_waste <= -1) { cg_span_t span; /* Check if size supported else bail out */ if (!dev->driver_vtable->texture_2d_can_create(dev, max_width, max_height, internal_format)) { _cg_set_error(error, CG_TEXTURE_ERROR, CG_TEXTURE_ERROR_SIZE, "Sliced texture size of %d x %d not possible " "with max waste set to -1", width, height); return false; } n_x_slices = 1; n_y_slices = 1; /* Init span arrays */ tex_2ds->slice_x_spans = c_array_sized_new(false, false, sizeof(cg_span_t), 1); tex_2ds->slice_y_spans = c_array_sized_new(false, false, sizeof(cg_span_t), 1); /* Add a single span for width and height */ span.start = 0; span.size = max_width; span.waste = max_width - width; c_array_append_val(tex_2ds->slice_x_spans, span); span.size = max_height; span.waste = max_height - height; c_array_append_val(tex_2ds->slice_y_spans, span); } else { /* Decrease the size of largest slice until supported by GL */ while (!dev->driver_vtable->texture_2d_can_create(dev, max_width, max_height, internal_format)) { /* Alternate between width and height */ if (max_width > max_height) max_width /= 2; else max_height /= 2; if (max_width == 0 || max_height == 0) { /* Maybe it would be ok to just c_warn_if_reached() for this * codepath */ _cg_set_error(error, CG_TEXTURE_ERROR, CG_TEXTURE_ERROR_SIZE, "No suitable slice geometry found"); free_spans(tex_2ds); return false; } } /* Determine the slices required to cover the bitmap area */ n_x_slices = slices_for_size(width, max_width, max_waste, NULL); n_y_slices = slices_for_size(height, max_height, max_waste, NULL); /* Init span arrays with reserved size */ tex_2ds->slice_x_spans = c_array_sized_new(false, false, sizeof(cg_span_t), n_x_slices); tex_2ds->slice_y_spans = c_array_sized_new(false, false, sizeof(cg_span_t), n_y_slices); /* Fill span arrays with info */ slices_for_size(width, max_width, max_waste, tex_2ds->slice_x_spans); slices_for_size(height, max_height, max_waste, tex_2ds->slice_y_spans); } return true; }
void _cg_glsl_shader_set_source_with_boilerplate(cg_device_t *dev, GLuint shader_gl_handle, GLenum shader_gl_type, GLsizei count_in, const char **strings_in, const GLint *lengths_in) { const char *vertex_boilerplate; const char *fragment_boilerplate; const char **strings = c_alloca(sizeof(char *) * (count_in + 6)); GLint *lengths = c_alloca(sizeof(GLint) * (count_in + 6)); char *version_string; int count = 0; vertex_boilerplate = _CG_VERTEX_SHADER_BOILERPLATE; fragment_boilerplate = _CG_FRAGMENT_SHADER_BOILERPLATE; version_string = c_strdup_printf("#version %i\n\n", dev->glsl_version_to_use); strings[count] = version_string; lengths[count++] = -1; if (_cg_has_private_feature(dev, CG_PRIVATE_FEATURE_GL_EMBEDDED) && cg_has_feature(dev, CG_FEATURE_ID_TEXTURE_3D)) { static const char texture_3d_extension[] = "#extension GL_OES_texture_3D : enable\n"; strings[count] = texture_3d_extension; lengths[count++] = sizeof(texture_3d_extension) - 1; } if (shader_gl_type == GL_VERTEX_SHADER) { if (dev->glsl_version_to_use < 130) { strings[count] = "#define in attribute\n" "#define out varying\n"; lengths[count++] = -1; } else { /* To support source compatibility with glsl >= 1.3 which has * replaced * all of the texture sampler functions with one polymorphic * texture() * function we use the preprocessor to map the old names onto the * new * name... */ strings[count] = "#define texture2D texture\n" "#define texture3D texture\n" "#define textureRect texture\n"; lengths[count++] = -1; } strings[count] = vertex_boilerplate; lengths[count++] = strlen(vertex_boilerplate); } else if (shader_gl_type == GL_FRAGMENT_SHADER) { if (dev->glsl_version_to_use < 130) { strings[count] = "#define in varying\n" "\n" "#define cg_color_out gl_FragColor\n" "#define cg_depth_out gl_FragDepth\n"; lengths[count++] = -1; } strings[count] = fragment_boilerplate; lengths[count++] = strlen(fragment_boilerplate); if (dev->glsl_version_to_use >= 130) { /* FIXME: Support cg_depth_out. */ /* To support source compatibility with glsl >= 1.3 which has * replaced * all of the texture sampler functions with one polymorphic * texture() * function we use the preprocessor to map the old names onto the * new * name... */ strings[count] = "#define texture2D texture\n" "#define texture3D texture\n" "#define textureRect texture\n" "\n" "out vec4 cg_color_out;\n"; //"out vec4 cg_depth_out\n"; lengths[count++] = -1; } } memcpy(strings + count, strings_in, sizeof(char *) * count_in); if (lengths_in) memcpy(lengths + count, lengths_in, sizeof(GLint) * count_in); else { int i; for (i = 0; i < count_in; i++) lengths[count + i] = -1; /* null terminated */ } count += count_in; if (C_UNLIKELY(CG_DEBUG_ENABLED(CG_DEBUG_SHOW_SOURCE))) { c_string_t *buf = c_string_new(NULL); int i; c_string_append_printf(buf, "%s shader:\n", shader_gl_type == GL_VERTEX_SHADER ? "vertex" : "fragment"); for (i = 0; i < count; i++) if (lengths[i] != -1) c_string_append_len(buf, strings[i], lengths[i]); else c_string_append(buf, strings[i]); c_message("%s", buf->str); c_string_free(buf, true); } GE(dev, glShaderSource( shader_gl_handle, count, (const char **)strings, lengths)); c_free(version_string); }