Update thirdparty libs

This commit is contained in:
halx99 2023-01-21 14:37:18 +08:00
parent 1eb3675b48
commit 831ad310f5
84 changed files with 5556 additions and 4091 deletions

View File

@ -6,7 +6,7 @@
## astc
- [![Upstream](https://img.shields.io/github/v/release/ARM-software/astc-encoder?label=Upstream)](https://github.com/ARM-software/astc-encoder)
- Version: 4.1.0
- Version: 4.3.0
- License: Apache-2.0
## Box2D
@ -67,12 +67,12 @@
## Glad
- [![Upstream](https://img.shields.io/github/v/tag/Dav1dde/glad?label=Upstream)](https://github.com/Dav1dde/glad)
- Version: 2.0.2
- Version: 2.0.3
- License: MIT
## glfw
- [![Upstream](https://img.shields.io/github/v/release/glfw/glfw?label=Upstream)](https://github.com/glfw/glfw)
- Version: git df8d7bc on 31 Dec 2021 (4398)
- Version: git 57cbded on Dec 16, 2022 (4609)
- License: zlib
## glsl-optimizer (Apple Metal Render backend only)

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2020-2022 Arm Limited
// Copyright 2020-2023 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
@ -74,7 +74,7 @@
*
* The codec supports compressing single images, which can be either 2D images or volumetric 3D
* images. Calling code is responsible for any handling of aggregate types, such as mipmap chains,
* texture arrays, or sliced 3D textures
* texture arrays, or sliced 3D textures.
*
* Images are passed in as an astcenc_image structure. Inputs can be either 8-bit unorm, 16-bit
* half-float, or 32-bit float, as indicated by the data_type field.
@ -241,6 +241,9 @@ static const float ASTCENC_PRE_MEDIUM = 60.0f;
/** @brief The thorough quality search preset. */
static const float ASTCENC_PRE_THOROUGH = 98.0f;
/** @brief The thorough quality search preset. */
static const float ASTCENC_PRE_VERYTHOROUGH = 99.0f;
/** @brief The exhaustive, highest quality, search preset. */
static const float ASTCENC_PRE_EXHAUSTIVE = 100.0f;
@ -303,14 +306,6 @@ enum astcenc_type
*/
static const unsigned int ASTCENC_FLG_MAP_NORMAL = 1 << 0;
/**
* @brief Enable mask map compression.
*
* Input data will be treated a multi-layer mask map, where is is desirable for the color components
* to be treated independently for the purposes of error analysis.
*/
static const unsigned int ASTCENC_FLG_MAP_MASK = 1 << 1;
/**
* @brief Enable alpha weighting.
*
@ -373,7 +368,6 @@ static const unsigned int ASTCENC_FLG_MAP_RGBM = 1 << 6;
* @brief The bit mask of all valid flags.
*/
static const unsigned int ASTCENC_ALL_FLAGS =
ASTCENC_FLG_MAP_MASK |
ASTCENC_FLG_MAP_NORMAL |
ASTCENC_FLG_MAP_RGBM |
ASTCENC_FLG_USE_ALPHA_WEIGHT |
@ -440,11 +434,25 @@ struct astcenc_config
unsigned int tune_partition_count_limit;
/**
* @brief The maximum number of partitions searched (-partitionindexlimit).
* @brief The maximum number of partitions searched (-2partitionindexlimit).
*
* Valid values are between 1 and 1024.
*/
unsigned int tune_partition_index_limit;
unsigned int tune_2partition_index_limit;
/**
* @brief The maximum number of partitions searched (-3partitionindexlimit).
*
* Valid values are between 1 and 1024.
*/
unsigned int tune_3partition_index_limit;
/**
* @brief The maximum number of partitions searched (-4partitionindexlimit).
*
* Valid values are between 1 and 1024.
*/
unsigned int tune_4partition_index_limit;
/**
* @brief The maximum centile for block modes searched (-blockmodelimit).
@ -468,6 +476,27 @@ struct astcenc_config
*/
unsigned int tune_candidate_limit;
/**
* @brief The number of trial partitionings per search (-2partitioncandidatelimit).
*
* Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES.
*/
unsigned int tune_2partitioning_candidate_limit;
/**
* @brief The number of trial partitionings per search (-3partitioncandidatelimit).
*
* Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES.
*/
unsigned int tune_3partitioning_candidate_limit;
/**
* @brief The number of trial partitionings per search (-4partitioncandidatelimit).
*
* Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES.
*/
unsigned int tune_4partitioning_candidate_limit;
/**
* @brief The dB threshold for stopping block search (-dblimit).
*
@ -476,25 +505,15 @@ struct astcenc_config
float tune_db_limit;
/**
* @brief The amount of overshoot needed to early-out mode 0 fast path.
* @brief The amount of MSE overshoot needed to early-out trials.
*
* We have a fast-path for mode 0 (1 partition, 1 plane) which uses only essential block modes
* as an initial search. This can short-cut compression for simple blocks, but to avoid
* short-cutting too much we force this to overshoot the MSE threshold needed to hit the
* block-local db_limit e.g. 1.0 = no overshoot, 2.0 = need half the error to trigger.
*/
float tune_mode0_mse_overshoot;
/**
* @brief The amount of overshoot needed to early-out refinement.
* The first early-out is for 1 partition, 1 plane trials, where we try a minimal encode using
* the high probability block modes. This can short-cut compression for simple blocks.
*
* The codec will refine block candidates iteratively to improve the encoding, based on the
* @c tune_refinement_limit count. Earlier implementations will use all refinement iterations,
* even if the target threshold is reached. This tuning parameter allows an early out, but with
* an overshoot MSE threshold. Setting this to 1.0 will early-out as soon as the target is hit,
* but does reduce image quality vs the default behavior of over-refinement.
* The second early-out is for refinement trials, where we can exit refinement once quality is
* reached.
*/
float tune_refinement_mse_overshoot;
float tune_mse_overshoot;
/**
* @brief The threshold for skipping 3.1/4.1 trials (-2partitionlimitfactor).
@ -517,11 +536,6 @@ struct astcenc_config
*/
float tune_2_plane_early_out_limit_correlation;
/**
* @brief The threshold below which (inclusive) we stop testing low/high/low+high cutoffs.
*/
unsigned int tune_low_weight_count_limit;
#if defined(ASTCENC_DIAGNOSTICS)
/**
* @brief The path to save the diagnostic trace data to.

View File

@ -390,8 +390,6 @@ void compute_avgs_and_dirs_4_comp(
const image_block& blk,
partition_metrics pm[BLOCK_MAX_PARTITIONS]
) {
float texel_weight = hadd_s(blk.channel_weight) / 4.0f;
int partition_count = pi.partition_count;
promise(partition_count > 0);
@ -434,11 +432,6 @@ void compute_avgs_and_dirs_4_comp(
sum_wp += select(zero, texel_datum, tdm3);
}
sum_xp = sum_xp * texel_weight;
sum_yp = sum_yp * texel_weight;
sum_zp = sum_zp * texel_weight;
sum_wp = sum_wp * texel_weight;
vfloat4 prod_xp = dot(sum_xp, sum_xp);
vfloat4 prod_yp = dot(sum_yp, sum_yp);
vfloat4 prod_zp = dot(sum_zp, sum_zp);
@ -473,8 +466,6 @@ void compute_avgs_and_dirs_3_comp(
vfloat4 partition_averages[BLOCK_MAX_PARTITIONS];
compute_partition_averages_rgba(pi, blk, partition_averages);
float texel_weight = hadd_s(blk.channel_weight.swz<0, 1, 2>());
const float* data_vr = blk.data_r;
const float* data_vg = blk.data_g;
const float* data_vb = blk.data_b;
@ -482,8 +473,6 @@ void compute_avgs_and_dirs_3_comp(
// TODO: Data-driven permute would be useful to avoid this ...
if (omitted_component == 0)
{
texel_weight = hadd_s(blk.channel_weight.swz<1, 2, 3>());
partition_averages[0] = partition_averages[0].swz<1, 2, 3>();
partition_averages[1] = partition_averages[1].swz<1, 2, 3>();
partition_averages[2] = partition_averages[2].swz<1, 2, 3>();
@ -495,8 +484,6 @@ void compute_avgs_and_dirs_3_comp(
}
else if (omitted_component == 1)
{
texel_weight = hadd_s(blk.channel_weight.swz<0, 2, 3>());
partition_averages[0] = partition_averages[0].swz<0, 2, 3>();
partition_averages[1] = partition_averages[1].swz<0, 2, 3>();
partition_averages[2] = partition_averages[2].swz<0, 2, 3>();
@ -507,8 +494,6 @@ void compute_avgs_and_dirs_3_comp(
}
else if (omitted_component == 2)
{
texel_weight = hadd_s(blk.channel_weight.swz<0, 1, 3>());
partition_averages[0] = partition_averages[0].swz<0, 1, 3>();
partition_averages[1] = partition_averages[1].swz<0, 1, 3>();
partition_averages[2] = partition_averages[2].swz<0, 1, 3>();
@ -524,8 +509,6 @@ void compute_avgs_and_dirs_3_comp(
partition_averages[3] = partition_averages[3].swz<0, 1, 2>();
}
texel_weight = texel_weight * (1.0f / 3.0f);
unsigned int partition_count = pi.partition_count;
promise(partition_count > 0);
@ -563,10 +546,6 @@ void compute_avgs_and_dirs_3_comp(
sum_zp += select(zero, texel_datum, tdm2);
}
sum_xp = sum_xp * texel_weight;
sum_yp = sum_yp * texel_weight;
sum_zp = sum_zp * texel_weight;
vfloat4 prod_xp = dot(sum_xp, sum_xp);
vfloat4 prod_yp = dot(sum_yp, sum_yp);
vfloat4 prod_zp = dot(sum_zp, sum_zp);
@ -591,8 +570,6 @@ void compute_avgs_and_dirs_3_comp_rgb(
const image_block& blk,
partition_metrics pm[BLOCK_MAX_PARTITIONS]
) {
float texel_weight = hadd_s(blk.channel_weight.swz<0, 1, 2>()) * (1.0f / 3.0f);
unsigned int partition_count = pi.partition_count;
promise(partition_count > 0);
@ -632,10 +609,6 @@ void compute_avgs_and_dirs_3_comp_rgb(
sum_zp += select(zero, texel_datum, tdm2);
}
sum_xp = sum_xp * texel_weight;
sum_yp = sum_yp * texel_weight;
sum_zp = sum_zp * texel_weight;
vfloat4 prod_xp = dot(sum_xp, sum_xp);
vfloat4 prod_yp = dot(sum_yp, sum_yp);
vfloat4 prod_zp = dot(sum_zp, sum_zp);
@ -662,7 +635,6 @@ void compute_avgs_and_dirs_2_comp(
unsigned int component2,
partition_metrics pm[BLOCK_MAX_PARTITIONS]
) {
float texel_weight;
vfloat4 average;
const float* data_vr = nullptr;
@ -670,7 +642,6 @@ void compute_avgs_and_dirs_2_comp(
if (component1 == 0 && component2 == 1)
{
texel_weight = hadd_s(blk.channel_weight.swz<0, 1>()) / 2.0f;
average = blk.data_mean.swz<0, 1>();
data_vr = blk.data_r;
@ -678,7 +649,6 @@ void compute_avgs_and_dirs_2_comp(
}
else if (component1 == 0 && component2 == 2)
{
texel_weight = hadd_s(blk.channel_weight.swz<0, 2>()) / 2.0f;
average = blk.data_mean.swz<0, 2>();
data_vr = blk.data_r;
@ -688,7 +658,6 @@ void compute_avgs_and_dirs_2_comp(
{
assert(component1 == 1 && component2 == 2);
texel_weight = hadd_s(blk.channel_weight.swz<1, 2>()) / 2.0f;
average = blk.data_mean.swz<1, 2>();
data_vr = blk.data_g;
@ -714,7 +683,7 @@ void compute_avgs_and_dirs_2_comp(
average += vfloat2(data_vr[iwt], data_vg[iwt]);
}
average = average * (1.0f / static_cast<float>(texel_count));
average = average / static_cast<float>(texel_count);
}
pm[partition].avg = average;
@ -737,9 +706,6 @@ void compute_avgs_and_dirs_2_comp(
sum_yp += select(zero, texel_datum, tdm1);
}
sum_xp = sum_xp * texel_weight;
sum_yp = sum_yp * texel_weight;
vfloat4 prod_xp = dot(sum_xp, sum_xp);
vfloat4 prod_yp = dot(sum_yp, sum_yp);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2011-2022 Arm Limited
// Copyright 2011-2023 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
@ -330,17 +330,17 @@ static void init_decimation_info_2d(
for (unsigned int j = 0; j < wb.weight_count_of_texel[i]; j++)
{
di.texel_weights_int_4t[j][i] = wb.weights_of_texel[i][j];
di.texel_weights_float_4t[j][i] = static_cast<float>(wb.weights_of_texel[i][j]) * (1.0f / WEIGHTS_TEXEL_SUM);
di.texel_weights_4t[j][i] = wb.grid_weights_of_texel[i][j];
di.texel_weight_contribs_int_tr[j][i] = wb.weights_of_texel[i][j];
di.texel_weight_contribs_float_tr[j][i] = static_cast<float>(wb.weights_of_texel[i][j]) * (1.0f / WEIGHTS_TEXEL_SUM);
di.texel_weights_tr[j][i] = wb.grid_weights_of_texel[i][j];
}
// Init all 4 entries so we can rely on zeros for vectorization
for (unsigned int j = wb.weight_count_of_texel[i]; j < 4; j++)
{
di.texel_weights_int_4t[j][i] = 0;
di.texel_weights_float_4t[j][i] = 0.0f;
di.texel_weights_4t[j][i] = 0;
di.texel_weight_contribs_int_tr[j][i] = 0;
di.texel_weight_contribs_float_tr[j][i] = 0.0f;
di.texel_weights_tr[j][i] = 0;
}
}
@ -356,43 +356,30 @@ static void init_decimation_info_2d(
uint8_t texel = wb.texels_of_weight[i][j];
// Create transposed versions of these for better vectorization
di.weight_texel[j][i] = texel;
di.weights_flt[j][i] = static_cast<float>(wb.texel_weights_of_weight[i][j]);
di.weight_texels_tr[j][i] = texel;
di.weights_texel_contribs_tr[j][i] = static_cast<float>(wb.texel_weights_of_weight[i][j]);
// perform a layer of array unrolling. An aspect of this unrolling is that
// one of the texel-weight indexes is an identity-mapped index; we will use this
// fact to reorder the indexes so that the first one is the identity index.
int swap_idx = -1;
// Store the per-texel contribution of this weight for each texel it contributes to
di.texel_contrib_for_weight[j][i] = 0.0f;
for (unsigned int k = 0; k < 4; k++)
{
uint8_t dttw = di.texel_weights_4t[k][texel];
float dttwf = di.texel_weights_float_4t[k][texel];
uint8_t dttw = di.texel_weights_tr[k][texel];
float dttwf = di.texel_weight_contribs_float_tr[k][texel];
if (dttw == i && dttwf != 0.0f)
{
swap_idx = k;
di.texel_contrib_for_weight[j][i] = di.texel_weight_contribs_float_tr[k][texel];
break;
}
di.texel_weights_texel[i][j][k] = dttw;
di.texel_weights_float_texel[i][j][k] = dttwf;
}
if (swap_idx != 0)
{
uint8_t vi = di.texel_weights_texel[i][j][0];
float vf = di.texel_weights_float_texel[i][j][0];
di.texel_weights_texel[i][j][0] = di.texel_weights_texel[i][j][swap_idx];
di.texel_weights_float_texel[i][j][0] = di.texel_weights_float_texel[i][j][swap_idx];
di.texel_weights_texel[i][j][swap_idx] = vi;
di.texel_weights_float_texel[i][j][swap_idx] = vf;
}
}
// Initialize array tail so we can over-fetch with SIMD later to avoid loop tails
// Match last texel in active lane in SIMD group, for better gathers
uint8_t last_texel = di.weight_texel[texel_count_wt - 1][i];
uint8_t last_texel = di.weight_texels_tr[texel_count_wt - 1][i];
for (unsigned int j = texel_count_wt; j < max_texel_count_of_weight; j++)
{
di.weight_texel[j][i] = last_texel;
di.weights_flt[j][i] = 0.0f;
di.weight_texels_tr[j][i] = last_texel;
di.weights_texel_contribs_tr[j][i] = 0.0f;
}
}
@ -404,16 +391,16 @@ static void init_decimation_info_2d(
for (unsigned int j = 0; j < 4; j++)
{
di.texel_weights_float_4t[j][i] = 0;
di.texel_weights_4t[j][i] = 0;
di.texel_weights_int_4t[j][i] = 0;
di.texel_weight_contribs_float_tr[j][i] = 0;
di.texel_weights_tr[j][i] = 0;
di.texel_weight_contribs_int_tr[j][i] = 0;
}
}
// Initialize array tail so we can over-fetch with SIMD later to avoid loop tails
// Match last texel in active lane in SIMD group, for better gathers
unsigned int last_texel_count_wt = wb.texel_count_of_weight[weights_per_block - 1];
uint8_t last_texel = di.weight_texel[last_texel_count_wt - 1][weights_per_block - 1];
uint8_t last_texel = di.weight_texels_tr[last_texel_count_wt - 1][weights_per_block - 1];
unsigned int weights_per_block_simd = round_up_to_simd_multiple_vla(weights_per_block);
for (unsigned int i = weights_per_block; i < weights_per_block_simd; i++)
@ -422,8 +409,8 @@ static void init_decimation_info_2d(
for (unsigned int j = 0; j < max_texel_count_of_weight; j++)
{
di.weight_texel[j][i] = last_texel;
di.weights_flt[j][i] = 0.0f;
di.weight_texels_tr[j][i] = last_texel;
di.weights_texel_contribs_tr[j][i] = 0.0f;
}
}
@ -600,16 +587,16 @@ static void init_decimation_info_3d(
// Init all 4 entries so we can rely on zeros for vectorization
for (unsigned int j = 0; j < 4; j++)
{
di.texel_weights_int_4t[j][i] = 0;
di.texel_weights_float_4t[j][i] = 0.0f;
di.texel_weights_4t[j][i] = 0;
di.texel_weight_contribs_int_tr[j][i] = 0;
di.texel_weight_contribs_float_tr[j][i] = 0.0f;
di.texel_weights_tr[j][i] = 0;
}
for (unsigned int j = 0; j < wb.weight_count_of_texel[i]; j++)
{
di.texel_weights_int_4t[j][i] = wb.weights_of_texel[i][j];
di.texel_weights_float_4t[j][i] = static_cast<float>(wb.weights_of_texel[i][j]) * (1.0f / WEIGHTS_TEXEL_SUM);
di.texel_weights_4t[j][i] = wb.grid_weights_of_texel[i][j];
di.texel_weight_contribs_int_tr[j][i] = wb.weights_of_texel[i][j];
di.texel_weight_contribs_float_tr[j][i] = static_cast<float>(wb.weights_of_texel[i][j]) * (1.0f / WEIGHTS_TEXEL_SUM);
di.texel_weights_tr[j][i] = wb.grid_weights_of_texel[i][j];
}
}
@ -625,43 +612,30 @@ static void init_decimation_info_3d(
unsigned int texel = wb.texels_of_weight[i][j];
// Create transposed versions of these for better vectorization
di.weight_texel[j][i] = static_cast<uint8_t>(texel);
di.weights_flt[j][i] = static_cast<float>(wb.texel_weights_of_weight[i][j]);
di.weight_texels_tr[j][i] = static_cast<uint8_t>(texel);
di.weights_texel_contribs_tr[j][i] = static_cast<float>(wb.texel_weights_of_weight[i][j]);
// perform a layer of array unrolling. An aspect of this unrolling is that
// one of the texel-weight indexes is an identity-mapped index; we will use this
// fact to reorder the indexes so that the first one is the identity index.
int swap_idx = -1;
// Store the per-texel contribution of this weight for each texel it contributes to
di.texel_contrib_for_weight[j][i] = 0.0f;
for (unsigned int k = 0; k < 4; k++)
{
uint8_t dttw = di.texel_weights_4t[k][texel];
float dttwf = di.texel_weights_float_4t[k][texel];
uint8_t dttw = di.texel_weights_tr[k][texel];
float dttwf = di.texel_weight_contribs_float_tr[k][texel];
if (dttw == i && dttwf != 0.0f)
{
swap_idx = k;
di.texel_contrib_for_weight[j][i] = di.texel_weight_contribs_float_tr[k][texel];
break;
}
di.texel_weights_texel[i][j][k] = dttw;
di.texel_weights_float_texel[i][j][k] = dttwf;
}
if (swap_idx != 0)
{
uint8_t vi = di.texel_weights_texel[i][j][0];
float vf = di.texel_weights_float_texel[i][j][0];
di.texel_weights_texel[i][j][0] = di.texel_weights_texel[i][j][swap_idx];
di.texel_weights_float_texel[i][j][0] = di.texel_weights_float_texel[i][j][swap_idx];
di.texel_weights_texel[i][j][swap_idx] = vi;
di.texel_weights_float_texel[i][j][swap_idx] = vf;
}
}
// Initialize array tail so we can over-fetch with SIMD later to avoid loop tails
// Match last texel in active lane in SIMD group, for better gathers
uint8_t last_texel = di.weight_texel[texel_count_wt - 1][i];
uint8_t last_texel = di.weight_texels_tr[texel_count_wt - 1][i];
for (unsigned int j = texel_count_wt; j < max_texel_count_of_weight; j++)
{
di.weight_texel[j][i] = last_texel;
di.weights_flt[j][i] = 0.0f;
di.weight_texels_tr[j][i] = last_texel;
di.weights_texel_contribs_tr[j][i] = 0.0f;
}
}
@ -673,16 +647,16 @@ static void init_decimation_info_3d(
for (unsigned int j = 0; j < 4; j++)
{
di.texel_weights_float_4t[j][i] = 0;
di.texel_weights_4t[j][i] = 0;
di.texel_weights_int_4t[j][i] = 0;
di.texel_weight_contribs_float_tr[j][i] = 0;
di.texel_weights_tr[j][i] = 0;
di.texel_weight_contribs_int_tr[j][i] = 0;
}
}
// Initialize array tail so we can over-fetch with SIMD later to avoid loop tails
// Match last texel in active lane in SIMD group, for better gathers
int last_texel_count_wt = wb.texel_count_of_weight[weights_per_block - 1];
uint8_t last_texel = di.weight_texel[last_texel_count_wt - 1][weights_per_block - 1];
uint8_t last_texel = di.weight_texels_tr[last_texel_count_wt - 1][weights_per_block - 1];
unsigned int weights_per_block_simd = round_up_to_simd_multiple_vla(weights_per_block);
for (unsigned int i = weights_per_block; i < weights_per_block_simd; i++)
@ -691,8 +665,8 @@ static void init_decimation_info_3d(
for (int j = 0; j < max_texel_count_of_weight; j++)
{
di.weight_texel[j][i] = last_texel;
di.weights_flt[j][i] = 0.0f;
di.weight_texels_tr[j][i] = last_texel;
di.weights_texel_contribs_tr[j][i] = 0.0f;
}
}
@ -1006,7 +980,7 @@ static void construct_block_size_descriptor_2d(
}
/**
* @brief Allocate block modes and decimation tables for a single £D block size.
* @brief Allocate block modes and decimation tables for a single 3D block size.
*
* TODO: This function doesn't include all of the heuristics that we use for 2D block sizes such as
* the percentile mode cutoffs. If 3D becomes more widely used we should look at this.

View File

@ -40,24 +40,6 @@
#include "astcenc_internal.h"
/**
* @brief Determine the quantized value given a quantization level.
*
* @param quant_level The quantization level to use.
* @param value The value to convert. This may be outside of the 0-255 range and will be
* clamped before the value is looked up.
*
* @return The encoded quantized value. These are not necessarily in order; the compressor
* scrambles the values slightly to make hardware implementation easier.
*/
static inline int quant_color_clamp(
quant_method quant_level,
int value
) {
value = astc::clamp(value, 0, 255);
return color_quant_tables[quant_level - QUANT_6][value];
}
/**
* @brief Determine the quantized value given a quantization level.
*
@ -72,23 +54,7 @@ static inline uint8_t quant_color(
quant_method quant_level,
int value
) {
return color_quant_tables[quant_level - QUANT_6][value];
}
/**
* @brief Determine the unquantized value given a quantization level.
*
* @param quant_level The quantization level to use.
* @param value The value to convert.
*
* @return The encoded quantized value. These are not necessarily in order; the compressor
* scrambles the values slightly to make hardware implementation easier.
*/
static inline uint8_t unquant_color(
quant_method quant_level,
int value
) {
return color_unquant_tables[quant_level - QUANT_6][value];
return color_unquant_to_uquant_tables[quant_level - QUANT_6][value];
}
/**
@ -120,28 +86,20 @@ static void quantize_rgb(
float b1 = astc::clamp255f(color1.lane<2>() * scale);
int ri0, gi0, bi0, ri1, gi1, bi1;
int ri0b, gi0b, bi0b, ri1b, gi1b, bi1b;
float rgb0_addon = 0.5f;
float rgb1_addon = 0.5f;
do
{
ri0 = quant_color_clamp(quant_level, astc::flt2int_rd(r0 + rgb0_addon));
gi0 = quant_color_clamp(quant_level, astc::flt2int_rd(g0 + rgb0_addon));
bi0 = quant_color_clamp(quant_level, astc::flt2int_rd(b0 + rgb0_addon));
ri1 = quant_color_clamp(quant_level, astc::flt2int_rd(r1 + rgb1_addon));
gi1 = quant_color_clamp(quant_level, astc::flt2int_rd(g1 + rgb1_addon));
bi1 = quant_color_clamp(quant_level, astc::flt2int_rd(b1 + rgb1_addon));
ri0b = unquant_color(quant_level, ri0);
gi0b = unquant_color(quant_level, gi0);
bi0b = unquant_color(quant_level, bi0);
ri1b = unquant_color(quant_level, ri1);
gi1b = unquant_color(quant_level, gi1);
bi1b = unquant_color(quant_level, bi1);
ri0 = quant_color(quant_level, astc::max(astc::flt2int_rd(r0 + rgb0_addon), 0));
gi0 = quant_color(quant_level, astc::max(astc::flt2int_rd(g0 + rgb0_addon), 0));
bi0 = quant_color(quant_level, astc::max(astc::flt2int_rd(b0 + rgb0_addon), 0));
ri1 = quant_color(quant_level, astc::min(astc::flt2int_rd(r1 + rgb1_addon), 255));
gi1 = quant_color(quant_level, astc::min(astc::flt2int_rd(g1 + rgb1_addon), 255));
bi1 = quant_color(quant_level, astc::min(astc::flt2int_rd(b1 + rgb1_addon), 255));
rgb0_addon -= 0.2f;
rgb1_addon += 0.2f;
} while (ri0b + gi0b + bi0b > ri1b + gi1b + bi1b);
} while (ri0 + gi0 + bi0 > ri1 + gi1 + bi1);
output[0] = static_cast<uint8_t>(ri0);
output[1] = static_cast<uint8_t>(ri1);
@ -230,18 +188,9 @@ static bool try_quantize_rgb_blue_contract(
int gi1 = quant_color(quant_level, astc::flt2int_rtn(g1));
int bi1 = quant_color(quant_level, astc::flt2int_rtn(b1));
// Then unquantize again
int ru0 = unquant_color(quant_level, ri0);
int gu0 = unquant_color(quant_level, gi0);
int bu0 = unquant_color(quant_level, bi0);
int ru1 = unquant_color(quant_level, ri1);
int gu1 = unquant_color(quant_level, gi1);
int bu1 = unquant_color(quant_level, bi1);
// If color #1 is not larger than color #0 then blue-contraction cannot be used. Note that
// blue-contraction and quantization change this order, which is why we must test aftwards.
if (ru1 + gu1 + bu1 <= ru0 + gu0 + bu0)
// blue-contraction and quantization change this order, which is why we must test afterwards.
if (ri1 + gi1 + bi1 <= ri0 + gi0 + bi0)
{
return false;
}
@ -334,13 +283,9 @@ static bool try_quantize_rgb_delta(
int g0be = quant_color(quant_level, g0b);
int b0be = quant_color(quant_level, b0b);
r0b = unquant_color(quant_level, r0be);
g0b = unquant_color(quant_level, g0be);
b0b = unquant_color(quant_level, b0be);
r0b |= r0a & 0x100;
g0b |= g0a & 0x100;
b0b |= b0a & 0x100;
r0b = r0be | (r0a & 0x100);
g0b = g0be | (g0a & 0x100);
b0b = b0be | (b0a & 0x100);
// Get hold of the second value
int r1d = astc::flt2int_rtn(r1);
@ -377,45 +322,23 @@ static bool try_quantize_rgb_delta(
int g1de = quant_color(quant_level, g1d);
int b1de = quant_color(quant_level, b1d);
int r1du = unquant_color(quant_level, r1de);
int g1du = unquant_color(quant_level, g1de);
int b1du = unquant_color(quant_level, b1de);
if (((r1d ^ r1du) | (g1d ^ g1du) | (b1d ^ b1du)) & 0xC0)
if (((r1d ^ r1de) | (g1d ^ g1de) | (b1d ^ b1de)) & 0xC0)
{
return false;
}
// Check that the sum of the encoded offsets is nonnegative, else encoding fails
r1du &= 0x7f;
g1du &= 0x7f;
b1du &= 0x7f;
if (r1du & 0x40)
{
r1du -= 0x80;
}
if (g1du & 0x40)
{
g1du -= 0x80;
}
if (b1du & 0x40)
{
b1du -= 0x80;
}
if (r1du + g1du + b1du < 0)
// If the sum of offsets triggers blue-contraction then encoding fails
vint4 ep0(r0be, g0be, b0be, 0);
vint4 ep1(r1de, g1de, b1de, 0);
bit_transfer_signed(ep1, ep0);
if (hadd_rgb_s(ep1) < 0)
{
return false;
}
// Check that the offsets produce legitimate sums as well
r1du += r0b;
g1du += g0b;
b1du += b0b;
if (r1du < 0 || r1du > 0x1FF || g1du < 0 || g1du > 0x1FF || b1du < 0 || b1du > 0x1FF)
ep0 = ep0 + ep1;
if (any((ep0 < vint4(0)) | (ep0 > vint4(0xFF))))
{
return false;
}
@ -477,13 +400,9 @@ static bool try_quantize_rgb_delta_blue_contract(
int g0be = quant_color(quant_level, g0b);
int b0be = quant_color(quant_level, b0b);
r0b = unquant_color(quant_level, r0be);
g0b = unquant_color(quant_level, g0be);
b0b = unquant_color(quant_level, b0be);
r0b |= r0a & 0x100;
g0b |= g0a & 0x100;
b0b |= b0a & 0x100;
r0b = r0be | (r0a & 0x100);
g0b = g0be | (g0a & 0x100);
b0b = b0be | (b0a & 0x100);
// Get hold of the second value
int r1d = astc::flt2int_rtn(r1);
@ -521,47 +440,23 @@ static bool try_quantize_rgb_delta_blue_contract(
int g1de = quant_color(quant_level, g1d);
int b1de = quant_color(quant_level, b1d);
int r1du = unquant_color(quant_level, r1de);
int g1du = unquant_color(quant_level, g1de);
int b1du = unquant_color(quant_level, b1de);
if (((r1d ^ r1du) | (g1d ^ g1du) | (b1d ^ b1du)) & 0xC0)
if (((r1d ^ r1de) | (g1d ^ g1de) | (b1d ^ b1de)) & 0xC0)
{
return false;
}
// Check that the sum of the encoded offsets is negative, else encoding fails
// Note that this is inverse of the test for non-blue-contracted RGB.
r1du &= 0x7f;
g1du &= 0x7f;
b1du &= 0x7f;
if (r1du & 0x40)
{
r1du -= 0x80;
}
if (g1du & 0x40)
{
g1du -= 0x80;
}
if (b1du & 0x40)
{
b1du -= 0x80;
}
if (r1du + g1du + b1du >= 0)
// If the sum of offsets does not trigger blue-contraction then encoding fails
vint4 ep0(r0be, g0be, b0be, 0);
vint4 ep1(r1de, g1de, b1de, 0);
bit_transfer_signed(ep1, ep0);
if (hadd_rgb_s(ep1) >= 0)
{
return false;
}
// Check that the offsets produce legitimate sums as well
r1du += r0b;
g1du += g0b;
b1du += b0b;
if (r1du < 0 || r1du > 0x1FF || g1du < 0 || g1du > 0x1FF || b1du < 0 || b1du > 0x1FF)
ep0 = ep0 + ep1;
if (any((ep0 < vint4(0)) | (ep0 > vint4(0xFF))))
{
return false;
}
@ -607,7 +502,7 @@ static bool try_quantize_alpha_delta(
a0a <<= 1;
int a0b = a0a & 0xFF;
int a0be = quant_color(quant_level, a0b);
a0b = unquant_color(quant_level, a0be);
a0b = a0be;
a0b |= a0a & 0x100;
int a1d = astc::flt2int_rtn(a1);
a1d <<= 1;
@ -622,7 +517,7 @@ static bool try_quantize_alpha_delta(
a1d |= (a0b & 0x100) >> 1;
int a1de = quant_color(quant_level, a1d);
int a1du = unquant_color(quant_level, a1de);
int a1du = a1de;
if ((a1d ^ a1du) & 0xC0)
{
return false;
@ -685,8 +580,8 @@ static bool try_quantize_luminance_alpha_delta(
int a0b = a0a & 0xFF;
int l0be = quant_color(quant_level, l0b);
int a0be = quant_color(quant_level, a0b);
l0b = unquant_color(quant_level, l0be);
a0b = unquant_color(quant_level, a0be);
l0b = l0be;
a0b = a0be;
l0b |= l0a & 0x100;
a0b |= a0a & 0x100;
@ -714,8 +609,8 @@ static bool try_quantize_luminance_alpha_delta(
int l1de = quant_color(quant_level, l1d);
int a1de = quant_color(quant_level, a1d);
int l1du = unquant_color(quant_level, l1de);
int a1du = unquant_color(quant_level, a1de);
int l1du = l1de;
int a1du = a1de;
if ((l1d ^ l1du) & 0xC0)
{
@ -837,12 +732,8 @@ static void quantize_rgbs(
int gi = quant_color(quant_level, astc::flt2int_rtn(g));
int bi = quant_color(quant_level, astc::flt2int_rtn(b));
int ru = unquant_color(quant_level, ri);
int gu = unquant_color(quant_level, gi);
int bu = unquant_color(quant_level, bi);
float oldcolorsum = hadd_rgb_s(color) * scale;
float newcolorsum = static_cast<float>(ru + gu + bu);
float newcolorsum = static_cast<float>(ri + gi + bi);
float scalea = astc::clamp1f(color.lane<3>() * (oldcolorsum + 1e-10f) / (newcolorsum + 1e-10f));
int scale_idx = astc::flt2int_rtn(scalea * 256.0f);
@ -987,33 +878,29 @@ static void quantize_luminance_alpha(
* @param quant_level The quantization level to use.
* @param value The input unquantized value.
* @param[out] quant_value The quantized value.
* @param[out] unquant_value The unquantized value after quantization.
*/
static inline void quantize_and_unquantize_retain_top_two_bits(
quant_method quant_level,
uint8_t value,
uint8_t& quant_value,
uint8_t& unquant_value
uint8_t& quant_value
) {
int perform_loop;
uint8_t quantval;
uint8_t uquantval;
do
{
quantval = quant_color(quant_level, value);
uquantval = unquant_color(quant_level, quantval);
// Perform looping if the top two bits were modified by quant/unquant
perform_loop = (value & 0xC0) != (uquantval & 0xC0);
perform_loop = (value & 0xC0) != (quantval & 0xC0);
if ((uquantval & 0xC0) > (value & 0xC0))
if ((quantval & 0xC0) > (value & 0xC0))
{
// Quant/unquant rounded UP so that the top two bits changed;
// decrement the input in hopes that this will avoid rounding up.
value--;
}
else if ((uquantval & 0xC0) < (value & 0xC0))
else if ((quantval & 0xC0) < (value & 0xC0))
{
// Quant/unquant rounded DOWN so that the top two bits changed;
// decrement the input in hopes that this will avoid rounding down.
@ -1022,7 +909,6 @@ static inline void quantize_and_unquantize_retain_top_two_bits(
} while (perform_loop);
quant_value = quantval;
unquant_value = uquantval;
}
/**
@ -1030,34 +916,29 @@ static inline void quantize_and_unquantize_retain_top_two_bits(
*
* @param quant_level The quantization level to use.
* @param value The input unquantized value.
* @param[out] quant_value The quantized value.
* @param[out] unquant_value The unquantized value after quantization.
* @param[out] quant_value The quantized value in 0-255 range.
*/
static inline void quantize_and_unquantize_retain_top_four_bits(
quant_method quant_level,
uint8_t value,
uint8_t& quant_value,
uint8_t& unquant_value
uint8_t& quant_value
) {
uint8_t perform_loop;
uint8_t quantval;
uint8_t uquantval;
do
{
quantval = quant_color(quant_level, value);
uquantval = unquant_color(quant_level, quantval);
// Perform looping if the top four bits were modified by quant/unquant
perform_loop = (value & 0xF0) != (uquantval & 0xF0);
perform_loop = (value & 0xF0) != (quantval & 0xF0);
if ((uquantval & 0xF0) > (value & 0xF0))
if ((quantval & 0xF0) > (value & 0xF0))
{
// Quant/unquant rounded UP so that the top four bits changed;
// decrement the input value in hopes that this will avoid rounding up.
value--;
}
else if ((uquantval & 0xF0) < (value & 0xF0))
else if ((quantval & 0xF0) < (value & 0xF0))
{
// Quant/unquant rounded DOWN so that the top four bits changed;
// decrement the input value in hopes that this will avoid rounding down.
@ -1066,7 +947,6 @@ static inline void quantize_and_unquantize_retain_top_four_bits(
} while (perform_loop);
quant_value = quantval;
unquant_value = uquantval;
}
/**
@ -1177,11 +1057,10 @@ static void quantize_hdr_rgbo(
r_lowbits |= (mode_enc & 3) << 6;
uint8_t r_quantval;
uint8_t r_uquantval;
quantize_and_unquantize_retain_top_two_bits(
quant_level, static_cast<uint8_t>(r_lowbits), r_quantval, r_uquantval);
quant_level, static_cast<uint8_t>(r_lowbits), r_quantval);
r_intval = (r_intval & ~0x3f) | (r_uquantval & 0x3f);
r_intval = (r_intval & ~0x3f) | (r_quantval & 0x3f);
float r_fval = static_cast<float>(r_intval) * mode_rscale;
// Recompute G and B, then quantize and unquantize them
@ -1277,16 +1156,14 @@ static void quantize_hdr_rgbo(
uint8_t g_quantval;
uint8_t b_quantval;
uint8_t g_uquantval;
uint8_t b_uquantval;
quantize_and_unquantize_retain_top_four_bits(
quant_level, static_cast<uint8_t>(g_lowbits), g_quantval, g_uquantval);
quant_level, static_cast<uint8_t>(g_lowbits), g_quantval);
quantize_and_unquantize_retain_top_four_bits(
quant_level, static_cast<uint8_t>(b_lowbits), b_quantval, b_uquantval);
quant_level, static_cast<uint8_t>(b_lowbits), b_quantval);
g_intval = (g_intval & ~0x1f) | (g_uquantval & 0x1f);
b_intval = (b_intval & ~0x1f) | (b_uquantval & 0x1f);
g_intval = (g_intval & ~0x1f) | (g_quantval & 0x1f);
b_intval = (b_intval & ~0x1f) | (b_quantval & 0x1f);
g_fval = static_cast<float>(g_intval) * mode_rscale;
b_fval = static_cast<float>(b_intval) * mode_rscale;
@ -1350,10 +1227,9 @@ static void quantize_hdr_rgbo(
s_lowbits |= bit4 << 7;
uint8_t s_quantval;
uint8_t s_uquantval;
quantize_and_unquantize_retain_top_four_bits(
quant_level, static_cast<uint8_t>(s_lowbits), s_quantval, s_uquantval);
quant_level, static_cast<uint8_t>(s_lowbits), s_quantval);
output[0] = r_quantval;
output[1] = g_quantval;
@ -1393,9 +1269,8 @@ static void quantize_hdr_rgbo(
for (uint8_t i = 0; i < 4; i++)
{
uint8_t dummy;
quantize_and_unquantize_retain_top_four_bits(
quant_level, static_cast<uint8_t>(encvals[i]), output[i], dummy);
quant_level, static_cast<uint8_t>(encvals[i]), output[i]);
}
return;
@ -1535,7 +1410,7 @@ static void quantize_hdr_rgb(
int a_lowbits = a_intval & 0xFF;
int a_quantval = quant_color(quant_level, a_lowbits);
int a_uquantval = unquant_color(quant_level, a_quantval);
int a_uquantval = a_quantval;
a_intval = (a_intval & ~0xFF) | a_uquantval;
float a_fval = static_cast<float>(a_intval) * mode_rscale;
@ -1556,12 +1431,11 @@ static void quantize_hdr_rgb(
c_lowbits |= (a_intval & 0x100) >> 2;
uint8_t c_quantval;
uint8_t c_uquantval;
quantize_and_unquantize_retain_top_two_bits(
quant_level, static_cast<uint8_t>(c_lowbits), c_quantval, c_uquantval);
quant_level, static_cast<uint8_t>(c_lowbits), c_quantval);
c_intval = (c_intval & ~0x3F) | (c_uquantval & 0x3F);
c_intval = (c_intval & ~0x3F) | (c_quantval & 0x3F);
c_fval = static_cast<float>(c_intval) * mode_rscale;
// Recompute B0 and B1, then quantize and unquantize them
@ -1625,16 +1499,14 @@ static void quantize_hdr_rgb(
uint8_t b0_quantval;
uint8_t b1_quantval;
uint8_t b0_uquantval;
uint8_t b1_uquantval;
quantize_and_unquantize_retain_top_two_bits(
quant_level, static_cast<uint8_t>(b0_lowbits), b0_quantval, b0_uquantval);
quant_level, static_cast<uint8_t>(b0_lowbits), b0_quantval);
quantize_and_unquantize_retain_top_two_bits(
quant_level, static_cast<uint8_t>(b1_lowbits), b1_quantval, b1_uquantval);
quant_level, static_cast<uint8_t>(b1_lowbits), b1_quantval);
b0_intval = (b0_intval & ~0x3f) | (b0_uquantval & 0x3f);
b1_intval = (b1_intval & ~0x3f) | (b1_uquantval & 0x3f);
b0_intval = (b0_intval & ~0x3f) | (b0_quantval & 0x3f);
b1_intval = (b1_intval & ~0x3f) | (b1_quantval & 0x3f);
b0_fval = static_cast<float>(b0_intval) * mode_rscale;
b1_fval = static_cast<float>(b1_intval) * mode_rscale;
@ -1722,13 +1594,11 @@ static void quantize_hdr_rgb(
uint8_t d0_quantval;
uint8_t d1_quantval;
uint8_t d0_uquantval;
uint8_t d1_uquantval;
quantize_and_unquantize_retain_top_four_bits(
quant_level, static_cast<uint8_t>(d0_lowbits), d0_quantval, d0_uquantval);
quant_level, static_cast<uint8_t>(d0_lowbits), d0_quantval);
quantize_and_unquantize_retain_top_four_bits(
quant_level, static_cast<uint8_t>(d1_lowbits), d1_quantval, d1_uquantval);
quant_level, static_cast<uint8_t>(d1_lowbits), d1_quantval);
output[0] = static_cast<uint8_t>(a_quantval);
output[1] = c_quantval;
@ -1764,10 +1634,9 @@ static void quantize_hdr_rgb(
for (int i = 4; i < 6; i++)
{
uint8_t dummy;
int idx = astc::flt2int_rtn(vals[i] * 1.0f / 512.0f) + 128;
quantize_and_unquantize_retain_top_two_bits(
quant_level, static_cast<uint8_t>(idx), output[i], dummy);
quant_level, static_cast<uint8_t>(idx), output[i]);
}
return;
@ -1919,7 +1788,7 @@ static bool try_quantize_hdr_luminance_small_range(
v0 = lowval & 0x7F;
v0e = quant_color(quant_level, v0);
v0d = unquant_color(quant_level, v0e);
v0d = v0e;
if (v0d < 0x80)
{
@ -1929,7 +1798,7 @@ static bool try_quantize_hdr_luminance_small_range(
{
v1 = ((lowval >> 3) & 0xF0) | diffval;
v1e = quant_color(quant_level, v1);
v1d = unquant_color(quant_level, v1e);
v1d = v1e;
if ((v1d & 0xF0) == (v1 & 0xF0))
{
output[0] = static_cast<uint8_t>(v0e);
@ -1948,7 +1817,7 @@ static bool try_quantize_hdr_luminance_small_range(
v0 = (lowval & 0x7F) | 0x80;
v0e = quant_color(quant_level, v0);
v0d = unquant_color(quant_level, v0e);
v0d = v0e;
if ((v0d & 0x80) == 0)
{
return false;
@ -1963,7 +1832,7 @@ static bool try_quantize_hdr_luminance_small_range(
v1 = ((lowval >> 2) & 0xE0) | diffval;
v1e = quant_color(quant_level, v1);
v1d = unquant_color(quant_level, v1e);
v1d = v1e;
if ((v1d & 0xE0) != (v1 & 0xE0))
{
return false;
@ -2007,7 +1876,7 @@ static void quantize_hdr_alpha(
v6 = (val0 & 0x7F) | ((i & 1) << 7);
v6e = quant_color(quant_level, v6);
v6d = unquant_color(quant_level, v6e);
v6d = v6e;
if ((v6 ^ v6d) & 0x80)
{
@ -2026,7 +1895,7 @@ static void quantize_hdr_alpha(
v7 = ((i & 2) << 6) | ((val0 >> 7) << (6 - i)) | (diffval & mask);
v7e = quant_color(quant_level, v7);
v7d = unquant_color(quant_level, v7e);
v7d = v7e;
static const int testbits[3] { 0xE0, 0xF0, 0xF8 };
@ -2091,7 +1960,7 @@ uint8_t pack_color_endpoints(
switch (format)
{
case FMT_RGB:
if (quant_level <= 18)
if (quant_level <= QUANT_160)
{
if (try_quantize_rgb_delta_blue_contract(color0, color1, output, quant_level))
{
@ -2104,7 +1973,7 @@ uint8_t pack_color_endpoints(
break;
}
}
if (try_quantize_rgb_blue_contract(color0, color1, output, quant_level))
if (quant_level < QUANT_256 && try_quantize_rgb_blue_contract(color0, color1, output, quant_level))
{
retval = FMT_RGB;
break;
@ -2114,7 +1983,7 @@ uint8_t pack_color_endpoints(
break;
case FMT_RGBA:
if (quant_level <= 18)
if (quant_level <= QUANT_160)
{
if (try_quantize_rgba_delta_blue_contract(color0, color1, output, quant_level))
{
@ -2127,7 +1996,7 @@ uint8_t pack_color_endpoints(
break;
}
}
if (try_quantize_rgba_blue_contract(color0, color1, output, quant_level))
if (quant_level < QUANT_256 && try_quantize_rgba_blue_contract(color0, color1, output, quant_level))
{
retval = FMT_RGBA;
break;

View File

@ -23,43 +23,6 @@
#include "astcenc_internal.h"
/**
* @brief Unquantize a color.
*
* This function uses a lookup table as the quantization is encoded to make
* hardware implementations easier, and is not a simple lerp.
*
* @param quant_level The quantization level to use.
* @param inputq The input quantized color.
*
* @return The unquantized color.
*/
static ASTCENC_SIMD_INLINE vint4 unquant_color(
quant_method quant_level,
vint4 inputq
) {
const uint8_t* unq = color_unquant_tables[quant_level - QUANT_6];
return vint4(unq[inputq.lane<0>()], unq[inputq.lane<1>()],
unq[inputq.lane<2>()], unq[inputq.lane<3>()]);
}
/**
* @brief Determine the quantized value given a quantization level.
*
* @param quant_level The quantization level to use.
* @param value The value to convert. This may be outside of the 0-255 range and will be
* clamped before the value is looked up.
*
* @return The encoded quantized value. These are not necessarily in order; the compressor
* scrambles the values slightly to make hardware implementation easier.
*/
static inline uint8_t unquant_color(
quant_method quant_level,
int value
) {
return color_unquant_tables[quant_level - QUANT_6][value];
}
/**
* @brief Un-blue-contract a color.
*
@ -80,32 +43,19 @@ static ASTCENC_SIMD_INLINE vint4 uncontract_color(
/**
* @brief Unpack an LDR RGBA color that uses delta encoding.
*
* @param input0q The raw quantized endpoint 0 color.
* @param input1q The raw quantized endpoint 1 color deltas.
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input0 The packed endpoint 0 color.
* @param input1 The packed endpoint 1 color deltas.
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void rgba_delta_unpack(
vint4 input0q,
vint4 input1q,
quant_method quant_level,
vint4 input0,
vint4 input1,
vint4& output0,
vint4& output1
) {
// Unquantize color endpoints
vint4 input0 = unquant_color(quant_level, input0q);
vint4 input1 = unquant_color(quant_level, input1q);
// Perform bit-transfer
input0 = input0 | lsl<1>(input1 & 0x80);
input1 = input1 & 0x7F;
vmask4 mask = (input1 & 0x40) != vint4::zero();
input1 = select(input1, input1 - 0x80, mask);
// Scale
input0 = asr<1>(input0);
input1 = asr<1>(input1);
// Apply bit transfer
bit_transfer_signed(input1, input0);
// Apply blue-uncontraction if needed
int rgb_sum = hadd_rgb_s(input1);
@ -126,20 +76,18 @@ static void rgba_delta_unpack(
*
* Output alpha set to 255.
*
* @param input0q The raw quantized endpoint 0 color.
* @param input1q The raw quantized endpoint 1 color deltas.
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input0 The packed endpoint 0 color.
* @param input1 The packed endpoint 1 color deltas.
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void rgb_delta_unpack(
vint4 input0q,
vint4 input1q,
quant_method quant_level,
vint4 input0,
vint4 input1,
vint4& output0,
vint4& output1
) {
rgba_delta_unpack(input0q, input1q, quant_level, output0, output1);
rgba_delta_unpack(input0, input1, output0, output1);
output0.set_lane<3>(255);
output1.set_lane<3>(255);
}
@ -147,23 +95,17 @@ static void rgb_delta_unpack(
/**
* @brief Unpack an LDR RGBA color that uses direct encoding.
*
* @param input0q The raw quantized endpoint 0 color.
* @param input1q The raw quantized endpoint 1 color.
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input0 The packed endpoint 0 color.
* @param input1 The packed endpoint 1 color.
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void rgba_unpack(
vint4 input0q,
vint4 input1q,
quant_method quant_level,
vint4 input0,
vint4 input1,
vint4& output0,
vint4& output1
) {
// Unquantize color endpoints
vint4 input0 = unquant_color(quant_level, input0q);
vint4 input1 = unquant_color(quant_level, input1q);
// Apply blue-uncontraction if needed
if (hadd_rgb_s(input0) > hadd_rgb_s(input1))
{
@ -181,20 +123,18 @@ static void rgba_unpack(
*
* Output alpha set to 255.
*
* @param input0q The raw quantized endpoint 0 color.
* @param input1q The raw quantized endpoint 1 color.
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input0 The packed endpoint 0 color.
* @param input1 The packed endpoint 1 color.
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void rgb_unpack(
vint4 input0q,
vint4 input1q,
quant_method quant_level,
vint4 input0,
vint4 input1,
vint4& output0,
vint4& output1
) {
rgba_unpack(input0q, input1q, quant_level, output0, output1);
rgba_unpack(input0, input1, output0, output1);
output0.set_lane<3>(255);
output1.set_lane<3>(255);
}
@ -204,31 +144,24 @@ static void rgb_unpack(
*
* Note only the RGB channels use the scaled encoding, alpha uses direct.
*
* @param input0q The raw quantized endpoint 0 color.
* @param alpha1q The raw quantized endpoint 1 alpha value.
* @param scaleq The raw quantized scale.
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input0 The packed endpoint 0 color.
* @param alpha1 The packed endpoint 1 alpha value.
* @param scale The packed quantized scale.
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void rgb_scale_alpha_unpack(
vint4 input0q,
uint8_t alpha1q,
uint8_t scaleq,
quant_method quant_level,
vint4 input0,
uint8_t alpha1,
uint8_t scale,
vint4& output0,
vint4& output1
) {
// Unquantize color endpoints
vint4 input = unquant_color(quant_level, input0q);
uint8_t alpha1 = unquant_color(quant_level, alpha1q);
uint8_t scale = unquant_color(quant_level, scaleq);
output1 = input;
output1 = input0;
output1.set_lane<3>(alpha1);
output0 = asr<8>(input * scale);
output0.set_lane<3>(input.lane<3>());
output0 = asr<8>(input0 * scale);
output0.set_lane<3>(input0.lane<3>());
}
/**
@ -236,26 +169,21 @@ static void rgb_scale_alpha_unpack(
*
* Output alpha is 255.
*
* @param input0q The raw quantized endpoint 0 color.
* @param scaleq The raw quantized scale.
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input0 The packed endpoint 0 color.
* @param scale The packed scale.
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void rgb_scale_unpack(
vint4 input0q,
int scaleq,
quant_method quant_level,
vint4 input0,
int scale,
vint4& output0,
vint4& output1
) {
vint4 input = unquant_color(quant_level, input0q);
int scale = unquant_color(quant_level, scaleq);
output1 = input;
output1 = input0;
output1.set_lane<3>(255);
output0 = asr<8>(input * scale);
output0 = asr<8>(input0 * scale);
output0.set_lane<3>(255);
}
@ -264,19 +192,17 @@ static void rgb_scale_unpack(
*
* Output alpha is 255.
*
* @param input The raw quantized endpoints.
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints.
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void luminance_unpack(
const uint8_t input[2],
quant_method quant_level,
vint4& output0,
vint4& output1
) {
int lum0 = unquant_color(quant_level, input[0]);
int lum1 = unquant_color(quant_level, input[1]);
int lum0 = input[0];
int lum1 = input[1];
output0 = vint4(lum0, lum0, lum0, 255);
output1 = vint4(lum1, lum1, lum1, 255);
}
@ -286,19 +212,17 @@ static void luminance_unpack(
*
* Output alpha is 255.
*
* @param input The raw quantized endpoints (L0, L1).
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints (L0, L1).
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void luminance_delta_unpack(
const uint8_t input[2],
quant_method quant_level,
vint4& output0,
vint4& output1
) {
int v0 = unquant_color(quant_level, input[0]);
int v1 = unquant_color(quant_level, input[1]);
int v0 = input[0];
int v1 = input[1];
int l0 = (v0 >> 2) | (v1 & 0xC0);
int l1 = l0 + (v1 & 0x3F);
@ -311,21 +235,19 @@ static void luminance_delta_unpack(
/**
* @brief Unpack an LDR LA color that uses direct encoding.
*
* @param input The raw quantized endpoints (L0, L1, A0, A1).
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints (L0, L1, A0, A1).
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void luminance_alpha_unpack(
const uint8_t input[4],
quant_method quant_level,
vint4& output0,
vint4& output1
) {
int lum0 = unquant_color(quant_level, input[0]);
int lum1 = unquant_color(quant_level, input[1]);
int alpha0 = unquant_color(quant_level, input[2]);
int alpha1 = unquant_color(quant_level, input[3]);
int lum0 = input[0];
int lum1 = input[1];
int alpha0 = input[2];
int alpha1 = input[3];
output0 = vint4(lum0, lum0, lum0, alpha0);
output1 = vint4(lum1, lum1, lum1, alpha1);
}
@ -333,30 +255,34 @@ static void luminance_alpha_unpack(
/**
* @brief Unpack an LDR LA color that uses delta encoding.
*
* @param input The raw quantized endpoints (L0, L1, A0, A1).
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints (L0, L1, A0, A1).
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void luminance_alpha_delta_unpack(
const uint8_t input[4],
quant_method quant_level,
vint4& output0,
vint4& output1
) {
int lum0 = unquant_color(quant_level, input[0]);
int lum1 = unquant_color(quant_level, input[1]);
int alpha0 = unquant_color(quant_level, input[2]);
int alpha1 = unquant_color(quant_level, input[3]);
int lum0 = input[0];
int lum1 = input[1];
int alpha0 = input[2];
int alpha1 = input[3];
lum0 |= (lum1 & 0x80) << 1;
alpha0 |= (alpha1 & 0x80) << 1;
lum1 &= 0x7F;
alpha1 &= 0x7F;
if (lum1 & 0x40)
{
lum1 -= 0x80;
}
if (alpha1 & 0x40)
{
alpha1 -= 0x80;
}
lum0 >>= 1;
lum1 >>= 1;
@ -375,21 +301,19 @@ static void luminance_alpha_delta_unpack(
/**
* @brief Unpack an HDR RGB + offset encoding.
*
* @param input The raw quantized endpoints (packed and modal).
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints (packed and modal).
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void hdr_rgbo_unpack(
const uint8_t input[4],
quant_method quant_level,
vint4& output0,
vint4& output1
) {
int v0 = unquant_color(quant_level, input[0]);
int v1 = unquant_color(quant_level, input[1]);
int v2 = unquant_color(quant_level, input[2]);
int v3 = unquant_color(quant_level, input[3]);
int v0 = input[0];
int v1 = input[1];
int v2 = input[2];
int v3 = input[3];
int modeval = ((v0 & 0xC0) >> 6) | (((v1 & 0x80) >> 7) << 2) | (((v2 & 0x80) >> 7) << 3);
@ -527,24 +451,22 @@ static void hdr_rgbo_unpack(
/**
* @brief Unpack an HDR RGB direct encoding.
*
* @param input The raw quantized endpoints (packed and modal).
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints (packed and modal).
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void hdr_rgb_unpack(
const uint8_t input[6],
quant_method quant_level,
vint4& output0,
vint4& output1
) {
int v0 = unquant_color(quant_level, input[0]);
int v1 = unquant_color(quant_level, input[1]);
int v2 = unquant_color(quant_level, input[2]);
int v3 = unquant_color(quant_level, input[3]);
int v4 = unquant_color(quant_level, input[4]);
int v5 = unquant_color(quant_level, input[5]);
int v0 = input[0];
int v1 = input[1];
int v2 = input[2];
int v3 = input[3];
int v4 = input[4];
int v5 = input[5];
// extract all the fixed-placement bitfields
int modeval = ((v1 & 0x80) >> 7) | (((v2 & 0x80) >> 7) << 1) | (((v3 & 0x80) >> 7) << 2);
@ -695,21 +617,19 @@ static void hdr_rgb_unpack(
/**
* @brief Unpack an HDR RGB + LDR A direct encoding.
*
* @param input The raw quantized endpoints (packed and modal).
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints (packed and modal).
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void hdr_rgb_ldr_alpha_unpack(
const uint8_t input[8],
quant_method quant_level,
vint4& output0,
vint4& output1
) {
hdr_rgb_unpack(input, quant_level, output0, output1);
hdr_rgb_unpack(input, output0, output1);
int v6 = unquant_color(quant_level, input[6]);
int v7 = unquant_color(quant_level, input[7]);
int v6 = input[6];
int v7 = input[7];
output0.set_lane<3>(v6);
output1.set_lane<3>(v7);
}
@ -717,19 +637,17 @@ static void hdr_rgb_ldr_alpha_unpack(
/**
* @brief Unpack an HDR L (small range) direct encoding.
*
* @param input The raw quantized endpoints (packed and modal).
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints (packed and modal).
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void hdr_luminance_small_range_unpack(
const uint8_t input[2],
quant_method quant_level,
vint4& output0,
vint4& output1
) {
int v0 = unquant_color(quant_level, input[0]);
int v1 = unquant_color(quant_level, input[1]);
int v0 = input[0];
int v1 = input[1];
int y0, y1;
if (v0 & 0x80)
@ -745,7 +663,9 @@ static void hdr_luminance_small_range_unpack(
y1 += y0;
if (y1 > 0xFFF)
{
y1 = 0xFFF;
}
output0 = vint4(y0 << 4, y0 << 4, y0 << 4, 0x7800);
output1 = vint4(y1 << 4, y1 << 4, y1 << 4, 0x7800);
@ -754,19 +674,17 @@ static void hdr_luminance_small_range_unpack(
/**
* @brief Unpack an HDR L (large range) direct encoding.
*
* @param input The raw quantized endpoints (packed and modal).
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints (packed and modal).
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void hdr_luminance_large_range_unpack(
const uint8_t input[2],
quant_method quant_level,
vint4& output0,
vint4& output1
) {
int v0 = unquant_color(quant_level, input[0]);
int v1 = unquant_color(quant_level, input[1]);
int v0 = input[0];
int v1 = input[1];
int y0, y1;
if (v1 >= v0)
@ -787,20 +705,18 @@ static void hdr_luminance_large_range_unpack(
/**
* @brief Unpack an HDR A direct encoding.
*
* @param input The raw quantized endpoints (packed and modal).
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints (packed and modal).
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void hdr_alpha_unpack(
const uint8_t input[2],
quant_method quant_level,
int& output0,
int& output1
) {
int v6 = unquant_color(quant_level, input[0]);
int v7 = unquant_color(quant_level, input[1]);
int v6 = input[0];
int v7 = input[1];
int selector = ((v6 >> 7) & 1) | ((v7 >> 6) & 2);
v6 &= 0x7F;
@ -821,9 +737,13 @@ static void hdr_alpha_unpack(
v7 += v6;
if (v7 < 0)
{
v7 = 0;
}
else if (v7 > 0xFFF)
{
v7 = 0xFFF;
}
output0 = v6;
output1 = v7;
@ -836,21 +756,19 @@ static void hdr_alpha_unpack(
/**
* @brief Unpack an HDR RGBA direct encoding.
*
* @param input The raw quantized endpoints (packed and modal).
* @param quant_level The quantization level to use.
* @param[out] output0 The unpacked and unquantized endpoint 0 color.
* @param[out] output1 The unpacked and unquantized endpoint 1 color.
* @param input The packed endpoints (packed and modal).
* @param[out] output0 The unpacked endpoint 0 color.
* @param[out] output1 The unpacked endpoint 1 color.
*/
static void hdr_rgb_hdr_alpha_unpack(
const uint8_t input[8],
quant_method quant_level,
vint4& output0,
vint4& output1
) {
hdr_rgb_unpack(input, quant_level, output0, output1);
hdr_rgb_unpack(input, output0, output1);
int alpha0, alpha1;
hdr_alpha_unpack(input + 6, quant_level, alpha0, alpha1);
hdr_alpha_unpack(input + 6, alpha0, alpha1);
output0.set_lane<3>(alpha0);
output1.set_lane<3>(alpha1);
@ -860,7 +778,6 @@ static void hdr_rgb_hdr_alpha_unpack(
void unpack_color_endpoints(
astcenc_profile decode_mode,
int format,
quant_method quant_level,
const uint8_t* input,
bool& rgb_hdr,
bool& alpha_hdr,
@ -876,38 +793,38 @@ void unpack_color_endpoints(
switch (format)
{
case FMT_LUMINANCE:
luminance_unpack(input, quant_level, output0, output1);
luminance_unpack(input, output0, output1);
break;
case FMT_LUMINANCE_DELTA:
luminance_delta_unpack(input, quant_level, output0, output1);
luminance_delta_unpack(input, output0, output1);
break;
case FMT_HDR_LUMINANCE_SMALL_RANGE:
rgb_hdr = true;
alpha_hdr_default = true;
hdr_luminance_small_range_unpack(input, quant_level, output0, output1);
hdr_luminance_small_range_unpack(input, output0, output1);
break;
case FMT_HDR_LUMINANCE_LARGE_RANGE:
rgb_hdr = true;
alpha_hdr_default = true;
hdr_luminance_large_range_unpack(input, quant_level, output0, output1);
hdr_luminance_large_range_unpack(input, output0, output1);
break;
case FMT_LUMINANCE_ALPHA:
luminance_alpha_unpack(input, quant_level, output0, output1);
luminance_alpha_unpack(input, output0, output1);
break;
case FMT_LUMINANCE_ALPHA_DELTA:
luminance_alpha_delta_unpack(input, quant_level, output0, output1);
luminance_alpha_delta_unpack(input, output0, output1);
break;
case FMT_RGB_SCALE:
{
vint4 input0q(input[0], input[1], input[2], 0);
uint8_t scale = input[3];
rgb_scale_unpack(input0q, scale, quant_level, output0, output1);
rgb_scale_unpack(input0q, scale, output0, output1);
}
break;
@ -916,21 +833,21 @@ void unpack_color_endpoints(
vint4 input0q(input[0], input[1], input[2], input[4]);
uint8_t alpha1q = input[5];
uint8_t scaleq = input[3];
rgb_scale_alpha_unpack(input0q, alpha1q, scaleq, quant_level, output0, output1);
rgb_scale_alpha_unpack(input0q, alpha1q, scaleq, output0, output1);
}
break;
case FMT_HDR_RGB_SCALE:
rgb_hdr = true;
alpha_hdr_default = true;
hdr_rgbo_unpack(input, quant_level,output0, output1);
hdr_rgbo_unpack(input, output0, output1);
break;
case FMT_RGB:
{
vint4 input0q(input[0], input[2], input[4], 0);
vint4 input1q(input[1], input[3], input[5], 0);
rgb_unpack(input0q, input1q, quant_level, output0, output1);
rgb_unpack(input0q, input1q, output0, output1);
}
break;
@ -938,21 +855,21 @@ void unpack_color_endpoints(
{
vint4 input0q(input[0], input[2], input[4], 0);
vint4 input1q(input[1], input[3], input[5], 0);
rgb_delta_unpack(input0q, input1q, quant_level, output0, output1);
rgb_delta_unpack(input0q, input1q, output0, output1);
}
break;
case FMT_HDR_RGB:
rgb_hdr = true;
alpha_hdr_default = true;
hdr_rgb_unpack(input, quant_level, output0, output1);
hdr_rgb_unpack(input, output0, output1);
break;
case FMT_RGBA:
{
vint4 input0q(input[0], input[2], input[4], input[6]);
vint4 input1q(input[1], input[3], input[5], input[7]);
rgba_unpack(input0q, input1q, quant_level, output0, output1);
rgba_unpack(input0q, input1q, output0, output1);
}
break;
@ -960,19 +877,19 @@ void unpack_color_endpoints(
{
vint4 input0q(input[0], input[2], input[4], input[6]);
vint4 input1q(input[1], input[3], input[5], input[7]);
rgba_delta_unpack(input0q, input1q, quant_level, output0, output1);
rgba_delta_unpack(input0q, input1q, output0, output1);
}
break;
case FMT_HDR_RGB_LDR_ALPHA:
rgb_hdr = true;
hdr_rgb_ldr_alpha_unpack(input, quant_level, output0, output1);
hdr_rgb_ldr_alpha_unpack(input, output0, output1);
break;
case FMT_HDR_RGBA:
rgb_hdr = true;
alpha_hdr = true;
hdr_rgb_hdr_alpha_unpack(input, quant_level, output0, output1);
hdr_rgb_hdr_alpha_unpack(input, output0, output1);
break;
}

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2011-2022 Arm Limited
// Copyright 2011-2023 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
@ -82,7 +82,7 @@ static bool realign_weights_undecimated(
const quant_and_transfer_table& qat = quant_and_xfer_tables[weight_quant_level];
unsigned int max_plane = bm.is_dual_plane;
int plane2_component = bm.is_dual_plane ? scb.plane2_component : -1;
int plane2_component = scb.plane2_component;
vmask4 plane_mask = vint4::lane_id() == vint4(plane2_component);
// Decode the color endpoints
@ -99,7 +99,6 @@ static bool realign_weights_undecimated(
{
unpack_color_endpoints(decode_mode,
scb.color_formats[pa_idx],
scb.get_color_quant_mode(),
scb.color_values[pa_idx],
rgb_hdr, alpha_hdr,
endpnt0[pa_idx],
@ -207,7 +206,7 @@ static bool realign_weights_decimated(
assert(weight_count != bsd.texel_count);
unsigned int max_plane = bm.is_dual_plane;
int plane2_component = bm.is_dual_plane ? scb.plane2_component : -1;
int plane2_component = scb.plane2_component;
vmask4 plane_mask = vint4::lane_id() == vint4(plane2_component);
// Decode the color endpoints
@ -225,7 +224,6 @@ static bool realign_weights_decimated(
{
unpack_color_endpoints(decode_mode,
scb.color_formats[pa_idx],
scb.get_color_quant_mode(),
scb.color_values[pa_idx],
rgb_hdr, alpha_hdr,
endpnt0[pa_idx],
@ -279,17 +277,14 @@ static bool realign_weights_decimated(
promise(texels_to_evaluate > 0);
for (unsigned int te_idx = 0; te_idx < texels_to_evaluate; te_idx++)
{
unsigned int texel = di.weight_texel[te_idx][we_idx];
unsigned int texel = di.weight_texels_tr[te_idx][we_idx];
const uint8_t *texel_weights = di.texel_weights_texel[we_idx][te_idx];
const float *texel_weights_float = di.texel_weights_float_texel[we_idx][te_idx];
float tw_base = di.texel_contrib_for_weight[te_idx][we_idx];
float tw_base = texel_weights_float[0];
float weight_base = (uqw_base * tw_base
+ uq_weightsf[texel_weights[1]] * texel_weights_float[1])
+ (uq_weightsf[texel_weights[2]] * texel_weights_float[2]
+ uq_weightsf[texel_weights[3]] * texel_weights_float[3]);
float weight_base = (uq_weightsf[di.texel_weights_tr[0][texel]] * di.texel_weight_contribs_float_tr[0][texel]
+ uq_weightsf[di.texel_weights_tr[1][texel]] * di.texel_weight_contribs_float_tr[1][texel])
+ (uq_weightsf[di.texel_weights_tr[2][texel]] * di.texel_weight_contribs_float_tr[2][texel]
+ uq_weightsf[di.texel_weights_tr[3][texel]] * di.texel_weight_contribs_float_tr[3][texel]);
// Ideally this is integer rounded, but IQ gain it isn't worth the overhead
// float weight = astc::flt_rd(weight_base + 0.5f);
@ -424,11 +419,7 @@ static float compress_symbolic_block_for_partition_1plane(
// For each mode, use the angular method to compute a shift
compute_angular_endpoints_1plane(
config.tune_low_weight_count_limit,
only_always, bsd,
dec_weights_ideal,
max_weight_quant,
tmpbuf);
only_always, bsd, dec_weights_ideal, max_weight_quant, tmpbuf);
float* weight_low_value = tmpbuf.weight_low_value1;
float* weight_high_value = tmpbuf.weight_high_value1;
@ -448,7 +439,7 @@ static float compress_symbolic_block_for_partition_1plane(
unsigned int max_block_modes = only_always ? bsd.block_mode_count_1plane_always
: bsd.block_mode_count_1plane_selected;
promise(max_block_modes > 0);
for (unsigned int i = 0; i < max_block_modes; ++i)
for (unsigned int i = 0; i < max_block_modes; i++)
{
const block_mode& bm = bsd.block_modes[i];
@ -628,12 +619,12 @@ static float compress_symbolic_block_for_partition_1plane(
trace_add_data("error_prerealign", errorval);
best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);
// Average refinement improvement is 3.5% per iteration (allow 5%), but the first
// iteration can help more so we give it a extra 10% leeway. Use this knowledge to
// Average refinement improvement is 3.5% per iteration (allow 4.5%), but the first
// iteration can help more so we give it a extra 8% leeway. Use this knowledge to
// drive a heuristic to skip blocks that are unlikely to catch up with the best
// block we have already.
unsigned int iters_remaining = config.tune_refinement_limit - l;
float threshold = (0.05f * static_cast<float>(iters_remaining)) + 1.1f;
float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.08f;
if (errorval > (threshold * best_errorval_in_scb))
{
break;
@ -678,10 +669,10 @@ static float compress_symbolic_block_for_partition_1plane(
best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);
// Average refinement improvement is 3.5% per iteration, so skip blocks that are
// unlikely to catch up with the best block we have already. Assume a 5% per step to
// unlikely to catch up with the best block we have already. Assume a 4.5% per step to
// give benefit of the doubt ...
unsigned int iters_remaining = config.tune_refinement_limit - 1 - l;
float threshold = (0.05f * static_cast<float>(iters_remaining)) + 1.0f;
float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.0f;
if (errorval > (threshold * best_errorval_in_scb))
{
break;
@ -795,9 +786,7 @@ static float compress_symbolic_block_for_partition_2planes(
float min_wt_cutoff2 = hmin_s(select(err_max, min_ep2, err_mask));
compute_angular_endpoints_2planes(
config.tune_low_weight_count_limit,
bsd, dec_weights_ideal, max_weight_quant,
tmpbuf);
bsd, dec_weights_ideal, max_weight_quant, tmpbuf);
// For each mode (which specifies a decimation and a quantization):
// * Compute number of bits needed for the quantized weights
@ -964,12 +953,12 @@ static float compress_symbolic_block_for_partition_2planes(
trace_add_data("error_prerealign", errorval);
best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);
// Average refinement improvement is 3.5% per iteration (allow 5%), but the first
// iteration can help more so we give it a extra 10% leeway. Use this knowledge to
// Average refinement improvement is 3.5% per iteration (allow 4.5%), but the first
// iteration can help more so we give it a extra 8% leeway. Use this knowledge to
// drive a heuristic to skip blocks that are unlikely to catch up with the best
// block we have already.
unsigned int iters_remaining = config.tune_refinement_limit - l;
float threshold = (0.05f * static_cast<float>(iters_remaining)) + 1.1f;
float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.08f;
if (errorval > (threshold * best_errorval_in_scb))
{
break;
@ -1015,10 +1004,10 @@ static float compress_symbolic_block_for_partition_2planes(
best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);
// Average refinement improvement is 3.5% per iteration, so skip blocks that are
// unlikely to catch up with the best block we have already. Assume a 5% per step to
// unlikely to catch up with the best block we have already. Assume a 4.5% per step to
// give benefit of the doubt ...
unsigned int iters_remaining = config.tune_refinement_limit - 1 - l;
float threshold = (0.05f * static_cast<float>(iters_remaining)) + 1.0f;
float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.0f;
if (errorval > (threshold * best_errorval_in_scb))
{
break;
@ -1130,12 +1119,13 @@ static float prepare_block_statistics(
aa_var -= as * (as * rpt);
rg_cov *= astc::rsqrt(astc::max(rr_var * gg_var, 1e-30f));
rb_cov *= astc::rsqrt(astc::max(rr_var * bb_var, 1e-30f));
ra_cov *= astc::rsqrt(astc::max(rr_var * aa_var, 1e-30f));
gb_cov *= astc::rsqrt(astc::max(gg_var * bb_var, 1e-30f));
ga_cov *= astc::rsqrt(astc::max(gg_var * aa_var, 1e-30f));
ba_cov *= astc::rsqrt(astc::max(bb_var * aa_var, 1e-30f));
// These will give a NaN if a channel is constant - these are fixed up in the next step
rg_cov *= astc::rsqrt(rr_var * gg_var);
rb_cov *= astc::rsqrt(rr_var * bb_var);
ra_cov *= astc::rsqrt(rr_var * aa_var);
gb_cov *= astc::rsqrt(gg_var * bb_var);
ga_cov *= astc::rsqrt(gg_var * aa_var);
ba_cov *= astc::rsqrt(bb_var * aa_var);
if (astc::isnan(rg_cov)) rg_cov = 1.0f;
if (astc::isnan(rb_cov)) rb_cov = 1.0f;
@ -1144,7 +1134,7 @@ static float prepare_block_statistics(
if (astc::isnan(ga_cov)) ga_cov = 1.0f;
if (astc::isnan(ba_cov)) ba_cov = 1.0f;
float lowest_correlation = astc::min(fabsf(rg_cov), fabsf(rb_cov));
float lowest_correlation = astc::min(fabsf(rg_cov), fabsf(rb_cov));
lowest_correlation = astc::min(lowest_correlation, fabsf(ra_cov));
lowest_correlation = astc::min(lowest_correlation, fabsf(gb_cov));
lowest_correlation = astc::min(lowest_correlation, fabsf(ga_cov));
@ -1197,6 +1187,18 @@ void compress_block(
bool block_skip_two_plane = false;
int max_partitions = ctx.config.tune_partition_count_limit;
unsigned int requested_partition_indices[3] {
ctx.config.tune_2partition_index_limit,
ctx.config.tune_3partition_index_limit,
ctx.config.tune_4partition_index_limit
};
unsigned int requested_partition_trials[3] {
ctx.config.tune_2partitioning_candidate_limit,
ctx.config.tune_3partitioning_candidate_limit,
ctx.config.tune_4partitioning_candidate_limit
};
#if defined(ASTCENC_DIAGNOSTICS)
// Do this early in diagnostic builds so we can dump uniform metrics
// for every block. Do it later in release builds to avoid redundant work!
@ -1274,13 +1276,13 @@ void compress_block(
// compression and slightly reduces image quality.
float errorval_mult[2] {
1.0f / ctx.config.tune_mode0_mse_overshoot,
1.0f / ctx.config.tune_mse_overshoot,
1.0f
};
static const float errorval_overshoot = 1.0f / ctx.config.tune_refinement_mse_overshoot;
static const float errorval_overshoot = 1.0f / ctx.config.tune_mse_overshoot;
// Only enable MODE0 fast path (trial 0) if 2D and more than 25 texels
// Only enable MODE0 fast path (trial 0) if 2D, and more than 25 texels
int start_trial = 1;
if ((bsd.texel_count >= TUNE_MIN_TEXELS_MODE0_FASTPATH) && (bsd.zdim == 1))
{
@ -1351,7 +1353,7 @@ void compress_block(
// If attempting two planes is much worse than the best one plane result
// then further two plane searches are unlikely to help so move on ...
if (errorval > (best_errorvals_for_pcount[0] * 2.0f))
if (errorval > (best_errorvals_for_pcount[0] * 1.85f))
{
break;
}
@ -1366,13 +1368,19 @@ void compress_block(
// Find best blocks for 2, 3 and 4 partitions
for (int partition_count = 2; partition_count <= max_partitions; partition_count++)
{
unsigned int partition_indices[2] { 0 };
unsigned int partition_indices[TUNE_MAX_PARTITIONING_CANDIDATES];
find_best_partition_candidates(bsd, blk, partition_count,
ctx.config.tune_partition_index_limit,
partition_indices);
unsigned int requested_indices = requested_partition_indices[partition_count - 2];
for (unsigned int i = 0; i < 2; i++)
unsigned int requested_trials = requested_partition_trials[partition_count - 2];
requested_trials = astc::min(requested_trials, requested_indices);
unsigned int actual_trials = find_best_partition_candidates(
bsd, blk, partition_count, requested_indices, partition_indices, requested_trials);
float best_error_in_prev = best_errorvals_for_pcount[partition_count - 2];
for (unsigned int i = 0; i < actual_trials; i++)
{
TRACE_NODE(node1, "pass");
trace_add_data("partition_count", partition_count);
@ -1387,6 +1395,19 @@ void compress_block(
scb, tmpbuf, quant_limit);
best_errorvals_for_pcount[partition_count - 1] = astc::min(best_errorvals_for_pcount[partition_count - 1], errorval);
// If using N partitions doesn't improve much over using N-1 partitions then skip trying
// N+1. Error can dramatically improve if the data is correlated or non-correlated and
// aligns with a partitioning that suits that encoding, so for this inner loop check add
// a large error scale because the "other" trial could be a lot better.
float best_error = best_errorvals_for_pcount[partition_count - 1];
float best_error_scale = exit_thresholds_for_pcount[partition_count - 1] * 1.85f;
if (best_error > (best_error_in_prev * best_error_scale))
{
trace_add_data("skip", "tune_partition_early_out_limit_factor");
goto END_OF_TESTS;
}
if (errorval < error_threshold)
{
trace_add_data("exit", "quality hit");
@ -1396,7 +1417,6 @@ void compress_block(
// If using N partitions doesn't improve much over using N-1 partitions then skip trying N+1
float best_error = best_errorvals_for_pcount[partition_count - 1];
float best_error_in_prev = best_errorvals_for_pcount[partition_count - 2];
float best_error_scale = exit_thresholds_for_pcount[partition_count - 1];
if (best_error > (best_error_in_prev * best_error_scale))
{

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2011-2022 Arm Limited
// Copyright 2011-2023 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
@ -121,8 +121,8 @@ void unpack_weights(
promise(max_weight_count > 0);
for (int j = 0; j < max_weight_count; j++)
{
vint texel_weights(di.texel_weights_4t[j] + i);
vint texel_weights_int(di.texel_weights_int_4t[j] + i);
vint texel_weights(di.texel_weights_tr[j] + i);
vint texel_weights_int(di.texel_weight_contribs_int_tr[j] + i);
summed_value += vtable_8bt_32bi(tab0p, tab1p, tab2p, tab3p, texel_weights) * texel_weights_int;
}
@ -156,8 +156,8 @@ void unpack_weights(
promise(max_weight_count > 0);
for (int j = 0; j < max_weight_count; j++)
{
vint texel_weights(di.texel_weights_4t[j] + i);
vint texel_weights_int(di.texel_weights_int_4t[j] + i);
vint texel_weights(di.texel_weights_tr[j] + i);
vint texel_weights_int(di.texel_weight_contribs_int_tr[j] + i);
sum_plane1 += vtable_8bt_32bi(tab0_plane1p, tab1_plane1p, texel_weights) * texel_weights_int;
sum_plane2 += vtable_8bt_32bi(tab0_plane2p, tab1_plane2p, texel_weights) * texel_weights_int;
@ -286,7 +286,7 @@ void decompress_symbolic_block(
unpack_weights(bsd, scb, di, is_dual_plane, plane1_weights, plane2_weights);
// Now that we have endpoint colors and weights, we can unpack texel colors
int plane2_component = is_dual_plane ? scb.plane2_component : -1;
int plane2_component = scb.plane2_component;
vmask4 plane2_mask = vint4::lane_id() == vint4(plane2_component);
for (int i = 0; i < partition_count; i++)
@ -299,7 +299,6 @@ void decompress_symbolic_block(
unpack_color_endpoints(decode_mode,
scb.color_formats[i],
scb.get_color_quant_mode(),
scb.color_values[i],
rgb_lns, a_lns,
ep0, ep1);
@ -362,7 +361,6 @@ float compute_symbolic_block_difference_2plane(
unpack_color_endpoints(config.profile,
scb.color_formats[0],
scb.get_color_quant_mode(),
scb.color_values[0],
rgb_lns, a_lns,
ep0, ep1);
@ -457,7 +455,6 @@ float compute_symbolic_block_difference_1plane(
unpack_color_endpoints(config.profile,
scb.color_formats[i],
scb.get_color_quant_mode(),
scb.color_values[i],
rgb_lns, a_lns,
ep0, ep1);
@ -546,7 +543,6 @@ float compute_symbolic_block_difference_1plane_1partition(
unpack_color_endpoints(config.profile,
scb.color_formats[0],
scb.get_color_quant_mode(),
scb.color_values[0],
rgb_lns, a_lns,
ep0, ep1);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2011-2022 Arm Limited
// Copyright 2011-2023 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
@ -40,88 +40,95 @@ struct astcenc_preset_config
{
float quality;
unsigned int tune_partition_count_limit;
unsigned int tune_partition_index_limit;
unsigned int tune_2partition_index_limit;
unsigned int tune_3partition_index_limit;
unsigned int tune_4partition_index_limit;
unsigned int tune_block_mode_limit;
unsigned int tune_refinement_limit;
unsigned int tune_candidate_limit;
unsigned int tune_2partitioning_candidate_limit;
unsigned int tune_3partitioning_candidate_limit;
unsigned int tune_4partitioning_candidate_limit;
float tune_db_limit_a_base;
float tune_db_limit_b_base;
float tune_mode0_mse_overshoot;
float tune_refinement_mse_overshoot;
float tune_mse_overshoot;
float tune_2_partition_early_out_limit_factor;
float tune_3_partition_early_out_limit_factor;
float tune_2_plane_early_out_limit_correlation;
unsigned int tune_low_weight_count_limit;
};
/**
* @brief The static quality presets that are built-in for high bandwidth
* presets (x < 25 texels per block).
* @brief The static presets for high bandwidth encodings (x < 25 texels per block).
*/
static const std::array<astcenc_preset_config, 5> preset_configs_high {{
static const std::array<astcenc_preset_config, 6> preset_configs_high {{
{
ASTCENC_PRE_FASTEST,
2, 10, 43, 2, 2, 85.2f, 63.2f, 3.5f, 3.5f, 1.0f, 1.0f, 0.5f, 25
2, 10, 6, 4, 43, 2, 2, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.85f
}, {
ASTCENC_PRE_FAST,
3, 14, 55, 3, 3, 85.2f, 63.2f, 3.5f, 3.5f, 1.0f, 1.1f, 0.65f, 20
3, 18, 10, 8, 55, 3, 3, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.90f
}, {
ASTCENC_PRE_MEDIUM,
4, 28, 76, 3, 3, 95.0f, 70.0f, 2.5f, 2.5f, 1.2f, 1.25f, 0.85f, 16
4, 34, 28, 16, 77, 3, 3, 2, 2, 2, 95.0f, 70.0f, 2.5f, 1.1f, 1.05f, 0.95f
}, {
ASTCENC_PRE_THOROUGH,
4, 76, 93, 4, 4, 105.0f, 77.0f, 10.0f, 10.0f, 2.5f, 1.25f, 0.95f, 12
4, 82, 60, 30, 94, 4, 4, 3, 2, 2, 105.0f, 77.0f, 10.0f, 1.35f, 1.15f, 0.97f
}, {
ASTCENC_PRE_VERYTHOROUGH,
4, 256, 128, 64, 98, 4, 6, 20, 14, 8, 200.0f, 200.0f, 10.0f, 1.6f, 1.4f, 0.98f
}, {
ASTCENC_PRE_EXHAUSTIVE,
4, 1024, 100, 4, 4, 200.0f, 200.0f, 10.0f, 10.0f, 10.0f, 10.0f, 0.99f, 0
4, 512, 512, 512, 100, 4, 8, 32, 32, 32, 200.0f, 200.0f, 10.0f, 2.0f, 2.0f, 0.99f
}
}};
/**
* @brief The static quality presets that are built-in for medium bandwidth
* presets (25 <= x < 64 texels per block).
* @brief The static presets for medium bandwidth encodings (25 <= x < 64 texels per block).
*/
static const std::array<astcenc_preset_config, 5> preset_configs_mid {{
static const std::array<astcenc_preset_config, 6> preset_configs_mid {{
{
ASTCENC_PRE_FASTEST,
2, 10, 43, 2, 2, 85.2f, 63.2f, 3.5f, 3.5f, 1.0f, 1.0f, 0.5f, 20
2, 10, 6, 4, 43, 2, 2, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.80f
}, {
ASTCENC_PRE_FAST,
3, 15, 55, 3, 3, 85.2f, 63.2f, 3.5f, 3.5f, 1.0f, 1.1f, 0.5f, 16
3, 18, 12, 10, 55, 3, 3, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.85f
}, {
ASTCENC_PRE_MEDIUM,
4, 30, 76, 3, 3, 95.0f, 70.0f, 3.0f, 3.0f, 1.2f, 1.25f, 0.75f, 14
4, 34, 28, 16, 77, 3, 3, 2, 2, 2, 95.0f, 70.0f, 3.0f, 1.1f, 1.05f, 0.90f
}, {
ASTCENC_PRE_THOROUGH,
4, 76, 93, 4, 4, 105.0f, 77.0f, 10.0f, 10.0f, 2.5f, 1.25f, 0.95f, 10
4, 82, 60, 30, 94, 4, 4, 3, 2, 2, 105.0f, 77.0f, 10.0f, 1.4f, 1.2f, 0.95f
}, {
ASTCENC_PRE_VERYTHOROUGH,
4, 256, 128, 64, 98, 4, 6, 12, 8, 3, 200.0f, 200.0f, 10.0f, 1.6f, 1.4f, 0.98f
}, {
ASTCENC_PRE_EXHAUSTIVE,
4, 1024, 100, 4, 4, 200.0f, 200.0f, 10.0f, 10.0f, 10.0f, 10.0f, 0.99f, 0
4, 256, 256, 256, 100, 4, 8, 32, 32, 32, 200.0f, 200.0f, 10.0f, 2.0f, 2.0f, 0.99f
}
}};
/**
* @brief The static quality presets that are built-in for low bandwidth
* presets (64 <= x texels per block).
* @brief The static presets for low bandwidth encodings (64 <= x texels per block).
*/
static const std::array<astcenc_preset_config, 5> preset_configs_low {{
static const std::array<astcenc_preset_config, 6> preset_configs_low {{
{
ASTCENC_PRE_FASTEST,
2, 10, 40, 2, 2, 85.0f, 63.0f, 3.5f, 3.5f, 1.0f, 1.0f, 0.5f, 20
2, 10, 6, 4, 40, 2, 2, 2, 2, 2, 85.0f, 63.0f, 3.5f, 1.0f, 1.0f, 0.80f
}, {
ASTCENC_PRE_FAST,
2, 15, 55, 3, 3, 85.0f, 63.0f, 3.5f, 3.5f, 1.0f, 1.1f, 0.5f, 16
2, 18, 12, 10, 55, 3, 3, 2, 2, 2, 85.0f, 63.0f, 3.5f, 1.0f, 1.0f, 0.85f
}, {
ASTCENC_PRE_MEDIUM,
3, 30, 76, 3, 3, 95.0f, 70.0f, 3.5f, 3.5f, 1.2f, 1.25f, 0.65f, 12
3, 34, 28, 16, 77, 3, 3, 2, 2, 2, 95.0f, 70.0f, 3.5f, 1.1f, 1.05f, 0.90f
}, {
ASTCENC_PRE_THOROUGH,
4, 75, 92, 4, 4, 105.0f, 77.0f, 10.0f, 10.0f, 2.5f, 1.25f, 0.85f, 10
4, 82, 60, 30, 93, 4, 4, 3, 2, 2, 105.0f, 77.0f, 10.0f, 1.3f, 1.2f, 0.97f
}, {
ASTCENC_PRE_VERYTHOROUGH,
4, 256, 128, 64, 98, 4, 6, 9, 5, 2, 200.0f, 200.0f, 10.0f, 1.6f, 1.4f, 0.98f
}, {
ASTCENC_PRE_EXHAUSTIVE,
4, 1024, 100, 4, 4, 200.0f, 200.0f, 10.0f, 10.0f, 10.0f, 10.0f, 0.99f, 0
4, 256, 256, 256, 100, 4, 8, 32, 32, 32, 200.0f, 200.0f, 10.0f, 2.0f, 2.0f, 0.99f
}
}};
@ -266,8 +273,7 @@ static astcenc_error validate_flags(
}
// Flags field must only contain at most a single map type
exMask = ASTCENC_FLG_MAP_MASK
| ASTCENC_FLG_MAP_NORMAL
exMask = ASTCENC_FLG_MAP_NORMAL
| ASTCENC_FLG_MAP_RGBM;
if (popcount(flags & exMask) > 1)
{
@ -422,13 +428,17 @@ static astcenc_error validate_config(
config.rgbm_m_scale = astc::max(config.rgbm_m_scale, 1.0f);
config.tune_partition_count_limit = astc::clamp(config.tune_partition_count_limit, 1u, 4u);
config.tune_partition_index_limit = astc::clamp(config.tune_partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS);
config.tune_2partition_index_limit = astc::clamp(config.tune_2partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS);
config.tune_3partition_index_limit = astc::clamp(config.tune_3partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS);
config.tune_4partition_index_limit = astc::clamp(config.tune_4partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS);
config.tune_block_mode_limit = astc::clamp(config.tune_block_mode_limit, 1u, 100u);
config.tune_refinement_limit = astc::max(config.tune_refinement_limit, 1u);
config.tune_candidate_limit = astc::clamp(config.tune_candidate_limit, 1u, TUNE_MAX_TRIAL_CANDIDATES);
config.tune_2partitioning_candidate_limit = astc::clamp(config.tune_2partitioning_candidate_limit, 1u, TUNE_MAX_PARTITIONING_CANDIDATES);
config.tune_3partitioning_candidate_limit = astc::clamp(config.tune_3partitioning_candidate_limit, 1u, TUNE_MAX_PARTITIONING_CANDIDATES);
config.tune_4partitioning_candidate_limit = astc::clamp(config.tune_4partitioning_candidate_limit, 1u, TUNE_MAX_PARTITIONING_CANDIDATES);
config.tune_db_limit = astc::max(config.tune_db_limit, 0.0f);
config.tune_mode0_mse_overshoot = astc::max(config.tune_mode0_mse_overshoot, 1.0f);
config.tune_refinement_mse_overshoot = astc::max(config.tune_refinement_mse_overshoot, 1.0f);
config.tune_mse_overshoot = astc::max(config.tune_mse_overshoot, 1.0f);
config.tune_2_partition_early_out_limit_factor = astc::max(config.tune_2_partition_early_out_limit_factor, 0.0f);
config.tune_3_partition_early_out_limit_factor = astc::max(config.tune_3_partition_early_out_limit_factor, 0.0f);
config.tune_2_plane_early_out_limit_correlation = astc::max(config.tune_2_plane_early_out_limit_correlation, 0.0f);
@ -464,9 +474,23 @@ astcenc_error astcenc_config_init(
astcenc_config* configp
) {
astcenc_error status;
astcenc_config& config = *configp;
// Check basic library compatibility options here so they are checked early. Note, these checks
// are repeated in context_alloc for cases where callers use a manually defined config struct
status = validate_cpu_isa();
if (status != ASTCENC_SUCCESS)
{
return status;
}
status = validate_cpu_float();
if (status != ASTCENC_SUCCESS)
{
return status;
}
// Zero init all config fields; although most of will be over written
astcenc_config& config = *configp;
std::memset(&config, 0, sizeof(config));
// Process the block size
@ -493,7 +517,7 @@ astcenc_error astcenc_config_init(
return ASTCENC_ERR_BAD_QUALITY;
}
static const std::array<astcenc_preset_config, 5>* preset_configs;
static const std::array<astcenc_preset_config, 6>* preset_configs;
int texels_int = block_x * block_y * block_z;
if (texels_int < 25)
{
@ -525,21 +549,23 @@ astcenc_error astcenc_config_init(
if (start == end)
{
config.tune_partition_count_limit = (*preset_configs)[start].tune_partition_count_limit;
config.tune_partition_index_limit = (*preset_configs)[start].tune_partition_index_limit;
config.tune_2partition_index_limit = (*preset_configs)[start].tune_2partition_index_limit;
config.tune_3partition_index_limit = (*preset_configs)[start].tune_3partition_index_limit;
config.tune_4partition_index_limit = (*preset_configs)[start].tune_4partition_index_limit;
config.tune_block_mode_limit = (*preset_configs)[start].tune_block_mode_limit;
config.tune_refinement_limit = (*preset_configs)[start].tune_refinement_limit;
config.tune_candidate_limit = astc::min((*preset_configs)[start].tune_candidate_limit,
TUNE_MAX_TRIAL_CANDIDATES);
config.tune_candidate_limit = astc::min((*preset_configs)[start].tune_candidate_limit, TUNE_MAX_TRIAL_CANDIDATES);
config.tune_2partitioning_candidate_limit = astc::min((*preset_configs)[start].tune_2partitioning_candidate_limit, TUNE_MAX_PARTITIONING_CANDIDATES);
config.tune_3partitioning_candidate_limit = astc::min((*preset_configs)[start].tune_3partitioning_candidate_limit, TUNE_MAX_PARTITIONING_CANDIDATES);
config.tune_4partitioning_candidate_limit = astc::min((*preset_configs)[start].tune_4partitioning_candidate_limit, TUNE_MAX_PARTITIONING_CANDIDATES);
config.tune_db_limit = astc::max((*preset_configs)[start].tune_db_limit_a_base - 35 * ltexels,
(*preset_configs)[start].tune_db_limit_b_base - 19 * ltexels);
config.tune_mode0_mse_overshoot = (*preset_configs)[start].tune_mode0_mse_overshoot;
config.tune_refinement_mse_overshoot = (*preset_configs)[start].tune_refinement_mse_overshoot;
config.tune_mse_overshoot = (*preset_configs)[start].tune_mse_overshoot;
config.tune_2_partition_early_out_limit_factor = (*preset_configs)[start].tune_2_partition_early_out_limit_factor;
config.tune_3_partition_early_out_limit_factor =(*preset_configs)[start].tune_3_partition_early_out_limit_factor;
config.tune_2_plane_early_out_limit_correlation = (*preset_configs)[start].tune_2_plane_early_out_limit_correlation;
config.tune_low_weight_count_limit = (*preset_configs)[start].tune_low_weight_count_limit;
}
// Start and end node are not the same - so interpolate between them
else
@ -561,21 +587,27 @@ astcenc_error astcenc_config_init(
#define LERPUI(param) static_cast<unsigned int>(LERPI(param))
config.tune_partition_count_limit = LERPI(tune_partition_count_limit);
config.tune_partition_index_limit = LERPI(tune_partition_index_limit);
config.tune_2partition_index_limit = LERPI(tune_2partition_index_limit);
config.tune_3partition_index_limit = LERPI(tune_3partition_index_limit);
config.tune_4partition_index_limit = LERPI(tune_4partition_index_limit);
config.tune_block_mode_limit = LERPI(tune_block_mode_limit);
config.tune_refinement_limit = LERPI(tune_refinement_limit);
config.tune_candidate_limit = astc::min(LERPUI(tune_candidate_limit),
TUNE_MAX_TRIAL_CANDIDATES);
config.tune_2partitioning_candidate_limit = astc::min(LERPUI(tune_2partitioning_candidate_limit),
BLOCK_MAX_PARTITIONINGS);
config.tune_3partitioning_candidate_limit = astc::min(LERPUI(tune_3partitioning_candidate_limit),
BLOCK_MAX_PARTITIONINGS);
config.tune_4partitioning_candidate_limit = astc::min(LERPUI(tune_4partitioning_candidate_limit),
BLOCK_MAX_PARTITIONINGS);
config.tune_db_limit = astc::max(LERP(tune_db_limit_a_base) - 35 * ltexels,
LERP(tune_db_limit_b_base) - 19 * ltexels);
config.tune_mode0_mse_overshoot = LERP(tune_mode0_mse_overshoot);
config.tune_refinement_mse_overshoot = LERP(tune_refinement_mse_overshoot);
config.tune_mse_overshoot = LERP(tune_mse_overshoot);
config.tune_2_partition_early_out_limit_factor = LERP(tune_2_partition_early_out_limit_factor);
config.tune_3_partition_early_out_limit_factor = LERP(tune_3_partition_early_out_limit_factor);
config.tune_2_plane_early_out_limit_correlation = LERP(tune_2_plane_early_out_limit_correlation);
config.tune_low_weight_count_limit = LERPI(tune_low_weight_count_limit);
#undef LERP
#undef LERPI
#undef LERPUI
@ -632,12 +664,6 @@ astcenc_error astcenc_config_init(
// so force compressor to try harder here ...
config.tune_db_limit *= 1.03f;
}
else if (flags & ASTCENC_FLG_MAP_MASK)
{
// Masks are prone to blocking artifacts on mask edges
// so force compressor to try harder here ...
config.tune_db_limit *= 1.03f;
}
else if (flags & ASTCENC_FLG_MAP_RGBM)
{
config.rgbm_m_scale = 5.0f;
@ -676,13 +702,13 @@ astcenc_error astcenc_context_alloc(
astcenc_error status;
const astcenc_config& config = *configp;
status = validate_cpu_float();
status = validate_cpu_isa();
if (status != ASTCENC_SUCCESS)
{
return status;
}
status = validate_cpu_isa();
status = validate_cpu_float();
if (status != ASTCENC_SUCCESS)
{
return status;
@ -714,7 +740,7 @@ astcenc_error astcenc_context_alloc(
status = validate_config(ctx->config);
if (status != ASTCENC_SUCCESS)
{
delete ctx;
delete ctxo;
return status;
}
@ -1316,7 +1342,6 @@ astcenc_error astcenc_get_block_info(
unpack_color_endpoints(ctx->config.profile,
scb.color_formats[i],
scb.get_color_quant_mode(),
scb.color_values[i],
rgb_hdr, a_hdr,
endpnt[0], endpnt[1]);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2011-2022 Arm Limited
// Copyright 2011-2023 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
@ -46,6 +46,7 @@
* lines for endpoint selection.
*/
#include <limits>
#include "astcenc_internal.h"
/**
@ -361,29 +362,27 @@ static void count_partition_mismatch_bits(
unsigned int mismatch_counts[BLOCK_MAX_PARTITIONINGS]
) {
unsigned int active_count = bsd.partitioning_count_selected[partition_count - 1];
promise(active_count > 0);
if (partition_count == 2)
{
for (unsigned int i = 0; i < active_count; i++)
{
int bitcount = partition_mismatch2(bitmaps, bsd.coverage_bitmaps_2[i]);
mismatch_counts[i] = astc::max(bitcount, static_cast<int>(bsd.partitioning_valid_2[i]));
mismatch_counts[i] = partition_mismatch2(bitmaps, bsd.coverage_bitmaps_2[i]);
}
}
else if (partition_count == 3)
{
for (unsigned int i = 0; i < active_count; i++)
{
int bitcount = partition_mismatch3(bitmaps, bsd.coverage_bitmaps_3[i]);
mismatch_counts[i] = astc::max(bitcount, static_cast<int>(bsd.partitioning_valid_3[i]));
mismatch_counts[i] = partition_mismatch3(bitmaps, bsd.coverage_bitmaps_3[i]);
}
}
else
{
for (unsigned int i = 0; i < active_count; i++)
{
int bitcount = partition_mismatch4(bitmaps, bsd.coverage_bitmaps_4[i]);
mismatch_counts[i] = astc::max(bitcount, static_cast<int>(bsd.partitioning_valid_4[i]));
mismatch_counts[i] = partition_mismatch4(bitmaps, bsd.coverage_bitmaps_4[i]);
}
}
}
@ -402,6 +401,7 @@ static unsigned int get_partition_ordering_by_mismatch_bits(
const unsigned int mismatch_count[BLOCK_MAX_PARTITIONINGS],
unsigned int partition_ordering[BLOCK_MAX_PARTITIONINGS]
) {
promise(partitioning_count > 0);
unsigned int mscount[256] { 0 };
// Create the histogram of mismatch counts
@ -487,13 +487,61 @@ static unsigned int compute_kmeans_partition_ordering(
mismatch_counts, partition_ordering);
}
/**
* @brief Insert a partitioning into an order list of results, sorted by error.
*
* @param max_values The max number of entries in the best result arrays.
* @param this_error The error of the new entry.
* @param this_partition The partition ID of the new entry.
* @param[out] best_errors The array of best error values.
* @param[out] best_partitions The array of best partition values.
*/
static void insert_result(
unsigned int max_values,
float this_error,
unsigned int this_partition,
float* best_errors,
unsigned int* best_partitions)
{
promise(max_values > 0);
// Don't bother searching if the current worst error beats the new error
if (this_error >= best_errors[max_values - 1])
{
return;
}
// Else insert into the list in error-order
for (unsigned int i = 0; i < max_values; i++)
{
// Existing result is better - move on ...
if (this_error > best_errors[i])
{
continue;
}
// Move existing results down one
for (unsigned int j = max_values - 1; j > i; j--)
{
best_errors[j] = best_errors[j - 1];
best_partitions[j] = best_partitions[j - 1];
}
// Insert new result
best_errors[i] = this_error;
best_partitions[i] = this_partition;
break;
}
}
/* See header for documentation. */
void find_best_partition_candidates(
unsigned int find_best_partition_candidates(
const block_size_descriptor& bsd,
const image_block& blk,
unsigned int partition_count,
unsigned int partition_search_limit,
unsigned int best_partitions[2]
unsigned int best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES],
unsigned int requested_candidates
) {
// Constant used to estimate quantization error for a given partitioning; the optimal value for
// this depends on bitrate. These values have been determined empirically.
@ -520,17 +568,23 @@ void find_best_partition_candidates(
unsigned int partition_sequence[BLOCK_MAX_PARTITIONINGS];
unsigned int sequence_len = compute_kmeans_partition_ordering(bsd, blk, partition_count, partition_sequence);
partition_search_limit = astc::min(partition_search_limit, sequence_len);
requested_candidates = astc::min(partition_search_limit, requested_candidates);
bool uses_alpha = !blk.is_constant_channel(3);
// Partitioning errors assuming uncorrelated-chrominance endpoints
float uncor_best_error { ERROR_CALC_DEFAULT };
unsigned int uncor_best_partition { 0 };
float uncor_best_errors[TUNE_MAX_PARTITIONING_CANDIDATES];
unsigned int uncor_best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES];
// Partitioning errors assuming same-chrominance endpoints
// Store two so we can always return one different to uncorr
float samec_best_errors[2] { ERROR_CALC_DEFAULT, ERROR_CALC_DEFAULT };
unsigned int samec_best_partitions[2] { 0, 0 };
float samec_best_errors[TUNE_MAX_PARTITIONING_CANDIDATES];
unsigned int samec_best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES];
for (unsigned int i = 0; i < requested_candidates; i++)
{
uncor_best_errors[i] = ERROR_CALC_DEFAULT;
samec_best_errors[i] = ERROR_CALC_DEFAULT;
}
if (uses_alpha)
{
@ -604,25 +658,8 @@ void find_best_partition_candidates(
samec_error += dot_s(samec_vector * samec_vector, error_weights);
}
if (uncor_error < uncor_best_error)
{
uncor_best_error = uncor_error;
uncor_best_partition = partition;
}
if (samec_error < samec_best_errors[0])
{
samec_best_errors[1] = samec_best_errors[0];
samec_best_partitions[1] = samec_best_partitions[0];
samec_best_errors[0] = samec_error;
samec_best_partitions[0] = partition;
}
else if (samec_error < samec_best_errors[1])
{
samec_best_errors[1] = samec_error;
samec_best_partitions[1] = partition;
}
insert_result(requested_candidates, uncor_error, partition, uncor_best_errors, uncor_best_partitions);
insert_result(requested_candidates, samec_error, partition, samec_best_errors, samec_best_partitions);
}
}
else
@ -644,10 +681,10 @@ void find_best_partition_candidates(
partition_lines3& pl = plines[j];
pl.uncor_line.a = pm.avg;
pl.uncor_line.b = normalize_safe(pm.dir.swz<0, 1, 2>(), unit3());
pl.uncor_line.b = normalize_safe(pm.dir, unit3());
pl.samec_line.a = vfloat4::zero();
pl.samec_line.b = normalize_safe(pm.avg.swz<0, 1, 2>(), unit3());
pl.samec_line.b = normalize_safe(pm.avg, unit3());
pl.uncor_pline.amod = pl.uncor_line.a - pl.uncor_line.b * dot3(pl.uncor_line.a, pl.uncor_line.b);
pl.uncor_pline.bs = pl.uncor_line.b;
@ -689,50 +726,55 @@ void find_best_partition_candidates(
samec_error += dot3_s(samec_vector * samec_vector, error_weights);
}
if (uncor_error < uncor_best_error)
{
uncor_best_error = uncor_error;
uncor_best_partition = partition;
}
insert_result(requested_candidates, uncor_error, partition, uncor_best_errors, uncor_best_partitions);
insert_result(requested_candidates, samec_error, partition, samec_best_errors, samec_best_partitions);
}
}
if (samec_error < samec_best_errors[0])
{
samec_best_errors[1] = samec_best_errors[0];
samec_best_partitions[1] = samec_best_partitions[0];
bool best_is_uncor = uncor_best_partitions[0] > samec_best_partitions[0];
samec_best_errors[0] = samec_error;
samec_best_partitions[0] = partition;
}
else if (samec_error < samec_best_errors[1])
unsigned int interleave[2 * TUNE_MAX_PARTITIONING_CANDIDATES];
for (unsigned int i = 0; i < requested_candidates; i++)
{
if (best_is_uncor)
{
interleave[2 * i] = bsd.get_raw_partition_info(partition_count, uncor_best_partitions[i]).partition_index;
interleave[2 * i + 1] = bsd.get_raw_partition_info(partition_count, samec_best_partitions[i]).partition_index;
}
else
{
interleave[2 * i] = bsd.get_raw_partition_info(partition_count, samec_best_partitions[i]).partition_index;
interleave[2 * i + 1] = bsd.get_raw_partition_info(partition_count, uncor_best_partitions[i]).partition_index;
}
}
uint64_t bitmasks[1024/64] { 0 };
unsigned int emitted = 0;
// Deduplicate the first "requested" entries
for (unsigned int i = 0; i < requested_candidates * 2; i++)
{
unsigned int partition = interleave[i];
unsigned int word = partition / 64;
unsigned int bit = partition % 64;
bool written = bitmasks[word] & (1ull << bit);
if (!written)
{
best_partitions[emitted] = partition;
bitmasks[word] |= 1ull << bit;
emitted++;
if (emitted == requested_candidates)
{
samec_best_errors[1] = samec_error;
samec_best_partitions[1] = partition;
break;
}
}
}
// Same partition is best for both, so use this first unconditionally
if (uncor_best_partition == samec_best_partitions[0])
{
best_partitions[0] = samec_best_partitions[0];
best_partitions[1] = samec_best_partitions[1];
}
// Uncor is best
else if (uncor_best_error <= samec_best_errors[0])
{
best_partitions[0] = uncor_best_partition;
best_partitions[1] = samec_best_partitions[0];
}
// Samec is best
else
{
best_partitions[0] = samec_best_partitions[0];
best_partitions[1] = uncor_best_partition;
}
// Convert these back into canonical partition IDs for the rest of the codec
best_partitions[0] = bsd.get_raw_partition_info(partition_count, best_partitions[0]).partition_index;
best_partitions[1] = bsd.get_raw_partition_info(partition_count, best_partitions[1]).partition_index;
return emitted;
}
#endif

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2011-2022 Arm Limited
// Copyright 2011-2023 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
@ -41,10 +41,10 @@ static vfloat bilinear_infill_vla(
unsigned int index
) {
// Load the bilinear filter texel weight indexes in the decimated grid
vint weight_idx0 = vint(di.texel_weights_4t[0] + index);
vint weight_idx1 = vint(di.texel_weights_4t[1] + index);
vint weight_idx2 = vint(di.texel_weights_4t[2] + index);
vint weight_idx3 = vint(di.texel_weights_4t[3] + index);
vint weight_idx0 = vint(di.texel_weights_tr[0] + index);
vint weight_idx1 = vint(di.texel_weights_tr[1] + index);
vint weight_idx2 = vint(di.texel_weights_tr[2] + index);
vint weight_idx3 = vint(di.texel_weights_tr[3] + index);
// Load the bilinear filter weights from the decimated grid
vfloat weight_val0 = gatherf(weights, weight_idx0);
@ -53,10 +53,10 @@ static vfloat bilinear_infill_vla(
vfloat weight_val3 = gatherf(weights, weight_idx3);
// Load the weight contribution factors for each decimated weight
vfloat tex_weight_float0 = loada(di.texel_weights_float_4t[0] + index);
vfloat tex_weight_float1 = loada(di.texel_weights_float_4t[1] + index);
vfloat tex_weight_float2 = loada(di.texel_weights_float_4t[2] + index);
vfloat tex_weight_float3 = loada(di.texel_weights_float_4t[3] + index);
vfloat tex_weight_float0 = loada(di.texel_weight_contribs_float_tr[0] + index);
vfloat tex_weight_float1 = loada(di.texel_weight_contribs_float_tr[1] + index);
vfloat tex_weight_float2 = loada(di.texel_weight_contribs_float_tr[2] + index);
vfloat tex_weight_float3 = loada(di.texel_weight_contribs_float_tr[3] + index);
// Compute the bilinear interpolation to generate the per-texel weight
return (weight_val0 * tex_weight_float0 + weight_val1 * tex_weight_float1) +
@ -81,16 +81,16 @@ static vfloat bilinear_infill_vla_2(
unsigned int index
) {
// Load the bilinear filter texel weight indexes in the decimated grid
vint weight_idx0 = vint(di.texel_weights_4t[0] + index);
vint weight_idx1 = vint(di.texel_weights_4t[1] + index);
vint weight_idx0 = vint(di.texel_weights_tr[0] + index);
vint weight_idx1 = vint(di.texel_weights_tr[1] + index);
// Load the bilinear filter weights from the decimated grid
vfloat weight_val0 = gatherf(weights, weight_idx0);
vfloat weight_val1 = gatherf(weights, weight_idx1);
// Load the weight contribution factors for each decimated weight
vfloat tex_weight_float0 = loada(di.texel_weights_float_4t[0] + index);
vfloat tex_weight_float1 = loada(di.texel_weights_float_4t[1] + index);
vfloat tex_weight_float0 = loada(di.texel_weight_contribs_float_tr[0] + index);
vfloat tex_weight_float1 = loada(di.texel_weight_contribs_float_tr[1] + index);
// Compute the bilinear interpolation to generate the per-texel weight
return (weight_val0 * tex_weight_float0 + weight_val1 * tex_weight_float1);
@ -268,13 +268,13 @@ static void compute_ideal_colors_and_weights_2_comp(
for (unsigned int i = 0; i < partition_count; i++)
{
vfloat4 dir = pms[i].dir.swz<0, 1>();
vfloat4 dir = pms[i].dir;
if (hadd_s(dir) < 0.0f)
{
dir = vfloat4::zero() - dir;
}
line2 line { pms[i].avg.swz<0, 1>(), normalize_safe(dir, unit2()) };
line2 line { pms[i].avg, normalize_safe(dir, unit2()) };
float lowparam { 1e10f };
float highparam { -1e10f };
@ -691,8 +691,8 @@ float compute_error_of_weight_set_1plane(
const float* dec_weight_quant_uvalue
) {
vfloatacc error_summav = vfloatacc::zero();
float error_summa = 0.0f;
unsigned int texel_count = di.texel_count;
promise(texel_count > 0);
// Process SIMD-width chunks, safe to over-fetch - the extra space is zero initialized
if (di.max_texel_weight_count > 2)
@ -745,7 +745,7 @@ float compute_error_of_weight_set_1plane(
}
// Resolve the final scalar accumulator sum
return error_summa = hadd_s(error_summav);
return hadd_s(error_summav);
}
/* See header for documentation. */
@ -758,6 +758,7 @@ float compute_error_of_weight_set_2planes(
) {
vfloatacc error_summav = vfloatacc::zero();
unsigned int texel_count = di.texel_count;
promise(texel_count > 0);
// Process SIMD-width chunks, safe to over-fetch - the extra space is zero initialized
if (di.max_texel_weight_count > 2)
@ -862,8 +863,7 @@ void compute_ideal_weights_for_decimation(
// zero-initialized SIMD over-fetch region
if (is_direct)
{
unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count);
for (unsigned int i = 0; i < texel_count_simd; i += ASTCENC_SIMD_WIDTH)
for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
{
vfloat weight(ei.weights + i);
storea(weight, dec_weight_ideal_value + i);
@ -894,8 +894,8 @@ void compute_ideal_weights_for_decimation(
for (unsigned int j = 0; j < max_texel_count; j++)
{
vint texel(di.weight_texel[j] + i);
vfloat weight = loada(di.weights_flt[j] + i);
vint texel(di.weight_texels_tr[j] + i);
vfloat weight = loada(di.weights_texel_contribs_tr[j] + i);
if (!constant_wes)
{
@ -952,8 +952,8 @@ void compute_ideal_weights_for_decimation(
for (unsigned int j = 0; j < max_texel_count; j++)
{
vint texel(di.weight_texel[j] + i);
vfloat contrib_weight = loada(di.weights_flt[j] + i);
vint texel(di.weight_texels_tr[j] + i);
vfloat contrib_weight = loada(di.weights_texel_contribs_tr[j] + i);
if (!constant_wes)
{
@ -971,7 +971,7 @@ void compute_ideal_weights_for_decimation(
vfloat step = (error_change1 * chd_scale) / error_change0;
step = clamp(-stepsize, stepsize, step);
// Update the weight; note this can store negative values.
// Update the weight; note this can store negative values
storea(weight_val + step, dec_weight_ideal_value + i);
}
}
@ -1216,7 +1216,7 @@ void recompute_ideal_colors_1plane(
// Only compute a partition mean if more than one partition
if (partition_count > 1)
{
rgba_sum = vfloat4(1e-17f);
rgba_sum = vfloat4::zero();
promise(texel_count > 0);
for (unsigned int j = 0; j < texel_count; j++)
{
@ -1252,7 +1252,6 @@ void recompute_ideal_colors_1plane(
for (unsigned int j = 0; j < texel_count; j++)
{
unsigned int tix = texel_indexes[j];
vfloat4 rgba = blk.texel(tix);
float idx0 = undec_weight_ref[tix];
@ -1285,14 +1284,11 @@ void recompute_ideal_colors_1plane(
vfloat4 right_sum = vfloat4(right_sum_s) * color_weight;
vfloat4 lmrs_sum = vfloat3(left_sum_s, middle_sum_s, right_sum_s) * ls_weight;
vfloat4 weight_weight_sum = vfloat4(weight_weight_sum_s) * color_weight;
float psum = right_sum_s * hadd_rgb_s(color_weight);
color_vec_x = color_vec_x * color_weight;
color_vec_y = color_vec_y * color_weight;
// Initialize the luminance and scale vectors with a reasonable default
float scalediv = scale_min * (1.0f / astc::max(scale_max, 1e-10f));
float scalediv = scale_min / astc::max(scale_max, 1e-10f);
scalediv = astc::clamp1f(scalediv);
vfloat4 sds = scale_dir * scale_max;
@ -1344,32 +1340,38 @@ void recompute_ideal_colors_1plane(
if (fabsf(ls_det1) > (ls_mss1 * 1e-4f) && scale_ep0 == scale_ep0 && scale_ep1 == scale_ep1 && scale_ep0 < scale_ep1)
{
float scalediv2 = scale_ep0 * (1.0f / scale_ep1);
float scalediv2 = scale_ep0 / scale_ep1;
vfloat4 sdsm = scale_dir * scale_ep1;
rgbs_vectors[i] = vfloat4(sdsm.lane<0>(), sdsm.lane<1>(), sdsm.lane<2>(), scalediv2);
}
}
// Calculations specific to mode #7, the HDR RGB-scale mode
vfloat4 rgbq_sum = color_vec_x + color_vec_y;
rgbq_sum.set_lane<3>(hadd_rgb_s(color_vec_y));
vfloat4 rgbovec = compute_rgbo_vector(rgba_weight_sum, weight_weight_sum, rgbq_sum, psum);
rgbo_vectors[i] = rgbovec;
// We can get a failure due to the use of a singular (non-invertible) matrix
// If it failed, compute rgbo_vectors[] with a different method ...
if (astc::isnan(dot_s(rgbovec, rgbovec)))
// Calculations specific to mode #7, the HDR RGB-scale mode - skip if known LDR
if (blk.rgb_lns[0] || blk.alpha_lns[0])
{
vfloat4 v0 = ep.endpt0[i];
vfloat4 v1 = ep.endpt1[i];
vfloat4 weight_weight_sum = vfloat4(weight_weight_sum_s) * color_weight;
float psum = right_sum_s * hadd_rgb_s(color_weight);
float avgdif = hadd_rgb_s(v1 - v0) * (1.0f / 3.0f);
avgdif = astc::max(avgdif, 0.0f);
vfloat4 rgbq_sum = color_vec_x + color_vec_y;
rgbq_sum.set_lane<3>(hadd_rgb_s(color_vec_y));
vfloat4 avg = (v0 + v1) * 0.5f;
vfloat4 ep0 = avg - vfloat4(avgdif) * 0.5f;
rgbo_vectors[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), avgdif);
vfloat4 rgbovec = compute_rgbo_vector(rgba_weight_sum, weight_weight_sum, rgbq_sum, psum);
rgbo_vectors[i] = rgbovec;
// We can get a failure due to the use of a singular (non-invertible) matrix
// If it failed, compute rgbo_vectors[] with a different method ...
if (astc::isnan(dot_s(rgbovec, rgbovec)))
{
vfloat4 v0 = ep.endpt0[i];
vfloat4 v1 = ep.endpt1[i];
float avgdif = hadd_rgb_s(v1 - v0) * (1.0f / 3.0f);
avgdif = astc::max(avgdif, 0.0f);
vfloat4 avg = (v0 + v1) * 0.5f;
vfloat4 ep0 = avg - vfloat4(avgdif) * 0.5f;
rgbo_vectors[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), avgdif);
}
}
}
}
@ -1517,7 +1519,7 @@ void recompute_ideal_colors_2planes(
color_vec_x += cwprod - cwiprod;
scale_vec += vfloat2(om_idx0, idx0) * (ls_weight * scale);
weight_weight_sum += (color_weight * color_idx);
weight_weight_sum += color_idx;
}
vfloat4 left1_sum = vfloat4(left1_sum_s) * color_weight;
@ -1529,13 +1531,11 @@ void recompute_ideal_colors_2planes(
vfloat4 middle2_sum = vfloat4(middle2_sum_s) * color_weight;
vfloat4 right2_sum = vfloat4(right2_sum_s) * color_weight;
float psum = dot3_s(select(right1_sum, right2_sum, p2_mask), color_weight);
color_vec_x = color_vec_x * color_weight;
color_vec_y = color_vec_y * color_weight;
// Initialize the luminance and scale vectors with a reasonable default
float scalediv = scale_min * (1.0f / astc::max(scale_max, 1e-10f));
float scalediv = scale_min / astc::max(scale_max, 1e-10f);
scalediv = astc::clamp1f(scalediv);
vfloat4 sds = scale_dir * scale_max;
@ -1591,7 +1591,7 @@ void recompute_ideal_colors_2planes(
if (fabsf(ls_det1) > (ls_mss1 * 1e-4f) && scale_ep0 == scale_ep0 && scale_ep1 == scale_ep1 && scale_ep0 < scale_ep1)
{
float scalediv2 = scale_ep0 * (1.0f / scale_ep1);
float scalediv2 = scale_ep0 / scale_ep1;
vfloat4 sdsm = scale_dir * scale_ep1;
rgbs_vector = vfloat4(sdsm.lane<0>(), sdsm.lane<1>(), sdsm.lane<2>(), scalediv2);
}
@ -1631,26 +1631,32 @@ void recompute_ideal_colors_2planes(
ep.endpt1[0] = select(ep.endpt1[0], ep1, full_mask);
}
// Calculations specific to mode #7, the HDR RGB-scale mode
vfloat4 rgbq_sum = color_vec_x + color_vec_y;
rgbq_sum.set_lane<3>(hadd_rgb_s(color_vec_y));
rgbo_vector = compute_rgbo_vector(rgba_weight_sum, weight_weight_sum, rgbq_sum, psum);
// We can get a failure due to the use of a singular (non-invertible) matrix
// If it failed, compute rgbo_vectors[] with a different method ...
if (astc::isnan(dot_s(rgbo_vector, rgbo_vector)))
// Calculations specific to mode #7, the HDR RGB-scale mode - skip if known LDR
if (blk.rgb_lns[0] || blk.alpha_lns[0])
{
vfloat4 v0 = ep.endpt0[0];
vfloat4 v1 = ep.endpt1[0];
weight_weight_sum = weight_weight_sum * color_weight;
float psum = dot3_s(select(right1_sum, right2_sum, p2_mask), color_weight);
float avgdif = hadd_rgb_s(v1 - v0) * (1.0f / 3.0f);
avgdif = astc::max(avgdif, 0.0f);
vfloat4 rgbq_sum = color_vec_x + color_vec_y;
rgbq_sum.set_lane<3>(hadd_rgb_s(color_vec_y));
vfloat4 avg = (v0 + v1) * 0.5f;
vfloat4 ep0 = avg - vfloat4(avgdif) * 0.5f;
rgbo_vector = compute_rgbo_vector(rgba_weight_sum, weight_weight_sum, rgbq_sum, psum);
rgbo_vector = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), avgdif);
// We can get a failure due to the use of a singular (non-invertible) matrix
// If it failed, compute rgbo_vectors[] with a different method ...
if (astc::isnan(dot_s(rgbo_vector, rgbo_vector)))
{
vfloat4 v0 = ep.endpt0[0];
vfloat4 v1 = ep.endpt1[0];
float avgdif = hadd_rgb_s(v1 - v0) * (1.0f / 3.0f);
avgdif = astc::max(avgdif, 0.0f);
vfloat4 avg = (v0 + v1) * 0.5f;
vfloat4 ep0 = avg - vfloat4(avgdif) * 0.5f;
rgbo_vector = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), avgdif);
}
}
}

View File

@ -24,6 +24,7 @@
#include <array>
/** @brief Unpacked quint triplets <low,middle,high> for each packed value */
// TODO: Bitpack these into a uint16_t?
static const uint8_t quints_of_integer[128][3] {
{0, 0, 0}, {1, 0, 0}, {2, 0, 0}, {3, 0, 0},
{4, 0, 0}, {0, 4, 0}, {4, 4, 0}, {4, 4, 4},
@ -99,6 +100,7 @@ static const uint8_t integer_of_quints[5][5][5] {
};
/** @brief Unpacked trit quintuplets <low,...,high> for each packed value */
// TODO: Bitpack these into a uint16_t?
static const uint8_t trits_of_integer[256][5] {
{0, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {2, 0, 0, 0, 0}, {0, 0, 2, 0, 0},
{0, 1, 0, 0, 0}, {1, 1, 0, 0, 0}, {2, 1, 0, 0, 0}, {1, 0, 2, 0, 0},
@ -334,44 +336,41 @@ static const uint8_t integer_of_trits[3][3][3][3][3] {
*/
struct btq_count
{
/** @brief The quantization level. */
uint8_t quant;
/** @brief The number of bits. */
uint8_t bits;
uint8_t bits:6;
/** @brief The number of trits. */
uint8_t trits;
uint8_t trits:1;
/** @brief The number of quints. */
uint8_t quints;
uint8_t quints:1;
};
/**
* @brief The table of bits, trits, and quints needed for a quant encode.
*/
static const std::array<btq_count, 21> btq_counts {{
{ QUANT_2, 1, 0, 0 },
{ QUANT_3, 0, 1, 0 },
{ QUANT_4, 2, 0, 0 },
{ QUANT_5, 0, 0, 1 },
{ QUANT_6, 1, 1, 0 },
{ QUANT_8, 3, 0, 0 },
{ QUANT_10, 1, 0, 1 },
{ QUANT_12, 2, 1, 0 },
{ QUANT_16, 4, 0, 0 },
{ QUANT_20, 2, 0, 1 },
{ QUANT_24, 3, 1, 0 },
{ QUANT_32, 5, 0, 0 },
{ QUANT_40, 3, 0, 1 },
{ QUANT_48, 4, 1, 0 },
{ QUANT_64, 6, 0, 0 },
{ QUANT_80, 4, 0, 1 },
{ QUANT_96, 5, 1, 0 },
{ QUANT_128, 7, 0, 0 },
{ QUANT_160, 5, 0, 1 },
{ QUANT_192, 6, 1, 0 },
{ QUANT_256, 8, 0, 0 }
{ 1, 0, 0 }, // QUANT_2
{ 0, 1, 0 }, // QUANT_3
{ 2, 0, 0 }, // QUANT_4
{ 0, 0, 1 }, // QUANT_5
{ 1, 1, 0 }, // QUANT_6
{ 3, 0, 0 }, // QUANT_8
{ 1, 0, 1 }, // QUANT_10
{ 2, 1, 0 }, // QUANT_12
{ 4, 0, 0 }, // QUANT_16
{ 2, 0, 1 }, // QUANT_20
{ 3, 1, 0 }, // QUANT_24
{ 5, 0, 0 }, // QUANT_32
{ 3, 0, 1 }, // QUANT_40
{ 4, 1, 0 }, // QUANT_48
{ 6, 0, 0 }, // QUANT_64
{ 4, 0, 1 }, // QUANT_80
{ 5, 1, 0 }, // QUANT_96
{ 7, 0, 0 }, // QUANT_128
{ 5, 0, 1 }, // QUANT_160
{ 6, 1, 0 }, // QUANT_192
{ 8, 0, 0 } // QUANT_256
}};
/**
@ -382,44 +381,38 @@ static const std::array<btq_count, 21> btq_counts {{
*/
struct ise_size
{
/** @brief The quantization level. */
uint8_t quant;
/** @brief The scaling parameter. */
uint8_t scale;
/** @brief The rounding parameter. */
uint8_t round;
uint8_t scale:6;
/** @brief The divisor parameter. */
uint8_t divisor;
uint8_t divisor:2;
};
/**
* @brief The table of scale, round, and divisors needed for quant sizing.
*/
static const std::array<ise_size, 21> ise_sizes {{
{ QUANT_2, 1, 0, 1 },
{ QUANT_3, 8, 4, 5 },
{ QUANT_4, 2, 0, 1 },
{ QUANT_5, 7, 2, 3 },
{ QUANT_6, 13, 4, 5 },
{ QUANT_8, 3, 0, 1 },
{ QUANT_10, 10, 2, 3 },
{ QUANT_12, 18, 4, 5 },
{ QUANT_16, 4, 0, 1 },
{ QUANT_20, 13, 2, 3 },
{ QUANT_24, 23, 4, 5 },
{ QUANT_32, 5, 0, 1 },
{ QUANT_40, 16, 2, 3 },
{ QUANT_48, 28, 4, 5 },
{ QUANT_64, 6, 0, 1 },
{ QUANT_80, 19, 2, 3 },
{ QUANT_96, 33, 4, 5 },
{ QUANT_128, 7, 0, 1 },
{ QUANT_160, 22, 2, 3 },
{ QUANT_192, 38, 4, 5 },
{ QUANT_256, 8, 0, 1 }
{ 1, 0 }, // QUANT_2
{ 8, 2 }, // QUANT_3
{ 2, 0 }, // QUANT_4
{ 7, 1 }, // QUANT_5
{ 13, 2 }, // QUANT_6
{ 3, 0 }, // QUANT_8
{ 10, 1 }, // QUANT_10
{ 18, 2 }, // QUANT_12
{ 4, 0 }, // QUANT_16
{ 13, 1 }, // QUANT_20
{ 23, 2 }, // QUANT_24
{ 5, 0 }, // QUANT_32
{ 16, 1 }, // QUANT_40
{ 28, 2 }, // QUANT_48
{ 6, 0 }, // QUANT_64
{ 19, 1 }, // QUANT_80
{ 33, 2 }, // QUANT_96
{ 7, 0 }, // QUANT_128
{ 22, 1 }, // QUANT_160
{ 38, 2 }, // QUANT_192
{ 8, 0 } // QUANT_256
}};
/* See header for documentation. */
@ -435,7 +428,8 @@ unsigned int get_ise_sequence_bitcount(
}
auto& entry = ise_sizes[quant_level];
return (entry.scale * character_count + entry.round) / entry.divisor;
unsigned int divisor = (entry.divisor << 1) + 1;
return (entry.scale * character_count + divisor - 1) / divisor;
}
/**
@ -645,7 +639,6 @@ void encode_ise(
// Write out just bits
else
{
promise(character_count > 0);
for (unsigned int i = 0; i < character_count; i++)
{
write_bits(input_data[i], bits, bit_offset, output_data);
@ -685,10 +678,10 @@ void decode_ise(
if (trits)
{
static const unsigned int bits_to_read[5] { 2, 2, 1, 2, 1 };
static const unsigned int block_shift[5] { 0, 2, 4, 5, 7 };
static const unsigned int next_lcounter[5] { 1, 2, 3, 4, 0 };
static const unsigned int hcounter_incr[5] { 0, 0, 0, 0, 1 };
static const uint8_t bits_to_read[5] { 2, 2, 1, 2, 1 };
static const uint8_t block_shift[5] { 0, 2, 4, 5, 7 };
static const uint8_t next_lcounter[5] { 1, 2, 3, 4, 0 };
static const uint8_t hcounter_incr[5] { 0, 0, 0, 0, 1 };
unsigned int tdata = read_bits(bits_to_read[lcounter], bit_offset, input_data);
bit_offset += bits_to_read[lcounter];
tq_blocks[hcounter] |= tdata << block_shift[lcounter];
@ -698,10 +691,10 @@ void decode_ise(
if (quints)
{
static const unsigned int bits_to_read[3] { 3, 2, 2 };
static const unsigned int block_shift[3] { 0, 3, 5 };
static const unsigned int next_lcounter[3] { 1, 2, 0 };
static const unsigned int hcounter_incr[3] { 0, 0, 1 };
static const uint8_t bits_to_read[3] { 3, 2, 2 };
static const uint8_t block_shift[3] { 0, 3, 5 };
static const uint8_t next_lcounter[3] { 1, 2, 0 };
static const uint8_t hcounter_incr[3] { 0, 0, 1 };
unsigned int tdata = read_bits(bits_to_read[lcounter], bit_offset, input_data);
bit_offset += bits_to_read[lcounter];
tq_blocks[hcounter] |= tdata << block_shift[lcounter];
@ -714,6 +707,7 @@ void decode_ise(
if (trits)
{
unsigned int trit_blocks = (character_count + 4) / 5;
promise(trit_blocks > 0);
for (unsigned int i = 0; i < trit_blocks; i++)
{
const uint8_t *tritptr = trits_of_integer[tq_blocks[i]];
@ -728,6 +722,7 @@ void decode_ise(
if (quints)
{
unsigned int quint_blocks = (character_count + 2) / 3;
promise(quint_blocks > 0);
for (unsigned int i = 0; i < quint_blocks; i++)
{
const uint8_t *quintptr = quints_of_integer[tq_blocks[i]];

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2011-2022 Arm Limited
// Copyright 2011-2023 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
@ -130,7 +130,14 @@ static constexpr unsigned int TUNE_MIN_TEXELS_MODE0_FASTPATH { 24 };
*
* This can be dynamically reduced by the compression quality preset.
*/
static constexpr unsigned int TUNE_MAX_TRIAL_CANDIDATES { 4 };
static constexpr unsigned int TUNE_MAX_TRIAL_CANDIDATES { 8 };
/**
* @brief The maximum number of candidate partitionings tested for each encoding mode.
*
* This can be dynamically reduced by the compression quality preset.
*/
static constexpr unsigned int TUNE_MAX_PARTITIONING_CANDIDATES { 32 };
/**
* @brief The maximum quant level using full angular endpoint search method.
@ -147,10 +154,12 @@ static constexpr unsigned int TUNE_MAX_TRIAL_CANDIDATES { 4 };
*/
static constexpr unsigned int TUNE_MAX_ANGULAR_QUANT { 7 }; /* QUANT_12 */
static_assert((BLOCK_MAX_TEXELS % ASTCENC_SIMD_WIDTH) == 0,
"BLOCK_MAX_TEXELS must be multiple of ASTCENC_SIMD_WIDTH");
static_assert(BLOCK_MAX_TEXELS <= 216,
"BLOCK_MAX_TEXELS must not be greater than 216");
static_assert((BLOCK_MAX_WEIGHTS % ASTCENC_SIMD_WIDTH) == 0,
"BLOCK_MAX_WEIGHTS must be multiple of ASTCENC_SIMD_WIDTH");
@ -353,38 +362,50 @@ struct decimation_info
/** @brief The number of stored weights in the Z dimension. */
uint8_t weight_z;
/** @brief The number of stored weights that contribute to each texel, between 1 and 4. */
/**
* @brief The number of weights that contribute to each texel.
* Value is between 1 and 4.
*/
uint8_t texel_weight_count[BLOCK_MAX_TEXELS];
/** @brief The weight index of the N weights that need to be interpolated for each texel. */
uint8_t texel_weights_4t[4][BLOCK_MAX_TEXELS];
/**
* @brief The weight index of the N weights that are interpolated for each texel.
* Stored transposed to improve vectorization.
*/
uint8_t texel_weights_tr[4][BLOCK_MAX_TEXELS];
/** @brief The bilinear interpolation weighting of the N input weights for each texel, between 0 and 16. */
uint8_t texel_weights_int_4t[4][BLOCK_MAX_TEXELS];
/**
* @brief The bilinear contribution of the N weights that are interpolated for each texel.
* Value is between 0 and 16, stored transposed to improve vectorization.
*/
uint8_t texel_weight_contribs_int_tr[4][BLOCK_MAX_TEXELS];
/** @brief The bilinear interpolation weighting of the N input weights for each texel, between 0 and 1. */
alignas(ASTCENC_VECALIGN) float texel_weights_float_4t[4][BLOCK_MAX_TEXELS];
/**
* @brief The bilinear contribution of the N weights that are interpolated for each texel.
* Value is between 0 and 1, stored transposed to improve vectorization.
*/
alignas(ASTCENC_VECALIGN) float texel_weight_contribs_float_tr[4][BLOCK_MAX_TEXELS];
/** @brief The number of texels that each stored weight contributes to. */
uint8_t weight_texel_count[BLOCK_MAX_WEIGHTS];
/** @brief The list of weights that contribute to each texel. */
uint8_t weight_texel[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS];
/** @brief The list of weight indices that contribute to each texel. */
alignas(ASTCENC_VECALIGN) float weights_flt[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS];
/**
* @brief The list of texels that use a specific weight index.
* Stored transposed to improve vectorization.
*/
uint8_t weight_texels_tr[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS];
/**
* @brief Folded structure for faster access:
* texel_weights_texel[i][j][.] = texel_weights[.][weight_texel[i][j]]
* @brief The bilinear contribution to the N texels that use each weight.
* Value is between 0 and 1, stored transposed to improve vectorization.
*/
uint8_t texel_weights_texel[BLOCK_MAX_WEIGHTS][BLOCK_MAX_TEXELS][4];
alignas(ASTCENC_VECALIGN) float weights_texel_contribs_tr[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS];
/**
* @brief Folded structure for faster access:
* texel_weights_float_texel[i][j][.] = texel_weights_float[.][weight_texel[i][j]]
* @brief The bilinear contribution to the Nth texel that uses each weight.
* Value is between 0 and 1, stored transposed to improve vectorization.
*/
float texel_weights_float_texel[BLOCK_MAX_WEIGHTS][BLOCK_MAX_TEXELS][4];
float texel_contrib_for_weight[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS];
};
/**
@ -579,13 +600,6 @@ struct block_size_descriptor
/** @brief The active texels for k-means partition selection. */
uint8_t kmeans_texels[BLOCK_MAX_KMEANS_TEXELS];
/**
* @brief Is 0 if this 2-partition is valid for compression 255 otherwise.
*
* Indexed by remapped index, not physical index.
*/
uint8_t partitioning_valid_2[BLOCK_MAX_PARTITIONINGS];
/**
* @brief The canonical 2-partition coverage pattern used during block partition search.
*
@ -593,13 +607,6 @@ struct block_size_descriptor
*/
uint64_t coverage_bitmaps_2[BLOCK_MAX_PARTITIONINGS][2];
/**
* @brief Is 0 if this 3-partition is valid for compression 255 otherwise.
*
* Indexed by remapped index, not physical index.
*/
uint8_t partitioning_valid_3[BLOCK_MAX_PARTITIONINGS];
/**
* @brief The canonical 3-partition coverage pattern used during block partition search.
*
@ -607,13 +614,6 @@ struct block_size_descriptor
*/
uint64_t coverage_bitmaps_3[BLOCK_MAX_PARTITIONINGS][3];
/**
* @brief Is 0 if this 4-partition is valid for compression 255 otherwise.
*
* Indexed by remapped index, not physical index.
*/
uint8_t partitioning_valid_4[BLOCK_MAX_PARTITIONINGS];
/**
* @brief The canonical 4-partition coverage pattern used during block partition search.
*
@ -1022,9 +1022,6 @@ struct dt_init_working_buffers
*/
struct quant_and_transfer_table
{
/** @brief The quantization level used. */
quant_method method;
/** @brief The unscrambled unquantized value. */
int8_t quant_to_unquant[32];
@ -1336,20 +1333,32 @@ bool is_legal_3d_block_size(
/**
* @brief The precomputed table for quantizing color values.
*
* Returned value is in the ASTC BISE scrambled order.
* Converts unquant value in 0-255 range into quant value in 0-255 range.
* No BISE scrambling is applied at this stage.
*
* Indexed by [quant_mode - 4][data_value].
*/
extern const uint8_t color_quant_tables[17][256];
extern const uint8_t color_unquant_to_uquant_tables[17][256];
/**
* @brief The precomputed table for unquantizing color values.
* @brief The precomputed table for packing quantized color values.
*
* Returned value is in the ASTC BISE scrambled order.
* Converts quant value in 0-255 range into packed quant value in 0-N range,
* with BISE scrambling applied.
*
* Indexed by [quant_mode - 4][data_value].
*/
extern const uint8_t color_unquant_tables[17][256];
extern const uint8_t color_uquant_to_scrambled_pquant_tables[17][256];
/**
* @brief The precomputed table for unpacking color values.
*
* Converts quant value in 0-N range into unpacked value in 0-255 range,
* with BISE unscrambling applied.
*
* Indexed by [quant_mode - 4][data_value].
*/
extern const uint8_t* color_scrambled_pquant_to_uquant_tables[17];
/**
* @brief The precomputed quant mode storage table.
@ -1366,11 +1375,11 @@ extern const int8_t quant_mode_table[10][128];
* Note that BISE can return strings that are not a whole number of bytes in length, and ASTC can
* start storing strings in a block at arbitrary bit offsets in the encoded data.
*
* @param quant_level The BISE alphabet size.
* @param character_count The number of characters in the string.
* @param input_data The unpacked string, one byte per character.
* @param[in,out] output_data The output packed string.
* @param bit_offset The starting offset in the output storage.
* @param quant_level The BISE alphabet size.
* @param character_count The number of characters in the string.
* @param input_data The unpacked string, one byte per character.
* @param[in,out] output_data The output packed string.
* @param bit_offset The starting offset in the output storage.
*/
void encode_ise(
quant_method quant_level,
@ -1457,11 +1466,11 @@ void compute_avgs_and_dirs_3_comp(
* This is a specialization of @c compute_avgs_and_dirs_3_comp where the omitted component is
* always alpha, a common case during partition search.
*
* @param pi The partition info for the current trial.
* @param blk The image block color data to be compressed.
* @param[out] pm The output partition metrics.
* - Only pi.partition_count array entries actually get initialized.
* - Direction vectors @c pm.dir are not normalized.
* @param pi The partition info for the current trial.
* @param blk The image block color data to be compressed.
* @param[out] pm The output partition metrics.
* - Only pi.partition_count array entries actually get initialized.
* - Direction vectors @c pm.dir are not normalized.
*/
void compute_avgs_and_dirs_3_comp_rgb(
const partition_info& pi,
@ -1492,11 +1501,11 @@ void compute_avgs_and_dirs_4_comp(
*
* This function computes the squared error when using these two representations.
*
* @param pi The partition info for the current trial.
* @param blk The image block color data to be compressed.
* @param[in,out] plines Processed line inputs, and line length outputs.
* @param[out] uncor_error The cumulative error for using the uncorrelated line.
* @param[out] samec_error The cumulative error for using the same chroma line.
* @param pi The partition info for the current trial.
* @param blk The image block color data to be compressed.
* @param[in,out] plines Processed line inputs, and line length outputs.
* @param[out] uncor_error The cumulative error for using the uncorrelated line.
* @param[out] samec_error The cumulative error for using the same chroma line.
*/
void compute_error_squared_rgb(
const partition_info& pi,
@ -1541,18 +1550,23 @@ void compute_error_squared_rgba(
* candidates; one assuming data has uncorrelated chroma and one assuming the
* data has correlated chroma. The best candidate is returned first in the list.
*
* @param bsd The block size information.
* @param blk The image block color data to compress.
* @param partition_count The number of partitions in the block.
* @param partition_search_limit The number of candidate partition encodings to trial.
* @param[out] best_partitions The best partition candidates.
* @param bsd The block size information.
* @param blk The image block color data to compress.
* @param partition_count The number of partitions in the block.
* @param partition_search_limit The number of candidate partition encodings to trial.
* @param[out] best_partitions The best partition candidates.
* @param requested_candidates The number of requested partitionings. May return fewer if
* candidates are not available.
*
* @return The actual number of candidates returned.
*/
void find_best_partition_candidates(
unsigned int find_best_partition_candidates(
const block_size_descriptor& bsd,
const image_block& blk,
unsigned int partition_count,
unsigned int partition_search_limit,
unsigned int best_partitions[2]);
unsigned int best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES],
unsigned int requested_candidates);
/* ============================================================================
Functionality for managing images and image related data.
@ -1566,10 +1580,10 @@ void find_best_partition_candidates(
*
* Results are written back into @c img->input_alpha_averages.
*
* @param img The input image data, also holds output data.
* @param alpha_kernel_radius The kernel radius (in pixels) for alpha mods.
* @param swz Input data component swizzle.
* @param[out] ag The average variance arguments to init.
* @param img The input image data, also holds output data.
* @param alpha_kernel_radius The kernel radius (in pixels) for alpha mods.
* @param swz Input data component swizzle.
* @param[out] ag The average variance arguments to init.
*
* @return The number of tasks in the processing stage.
*/
@ -1787,13 +1801,13 @@ float compute_error_of_weight_set_2planes(
* The user requests a base color endpoint mode in @c format, but the quantizer may choose a
* delta-based representation. It will report back the format variant it actually used.
*
* @param color0 The input unquantized color0 endpoint for absolute endpoint pairs.
* @param color1 The input unquantized color1 endpoint for absolute endpoint pairs.
* @param rgbs_color The input unquantized RGBS variant endpoint for same chroma endpoints.
* @param rgbo_color The input unquantized RGBS variant endpoint for HDR endpoints..
* @param format The desired base format.
* @param[out] output The output storage for the quantized colors/
* @param quant_level The quantization level requested.
* @param color0 The input unquantized color0 endpoint for absolute endpoint pairs.
* @param color1 The input unquantized color1 endpoint for absolute endpoint pairs.
* @param rgbs_color The input unquantized RGBS variant endpoint for same chroma endpoints.
* @param rgbo_color The input unquantized RGBS variant endpoint for HDR endpoints.
* @param format The desired base format.
* @param[out] output The output storage for the quantized colors/
* @param quant_level The quantization level requested.
*
* @return The actual endpoint mode used.
*/
@ -1807,11 +1821,12 @@ uint8_t pack_color_endpoints(
quant_method quant_level);
/**
* @brief Unpack a single pair of encoded and quantized color endpoints.
* @brief Unpack a single pair of encoded endpoints.
*
* Endpoints must be unscrambled and converted into the 0-255 range before calling this functions.
*
* @param decode_mode The decode mode (LDR, HDR).
* @param format The color endpoint mode used.
* @param quant_level The quantization level used.
* @param input The raw array of encoded input integers. The length of this array
* depends on @c format; it can be safely assumed to be large enough.
* @param[out] rgb_hdr Is the endpoint using HDR for the RGB channels?
@ -1822,7 +1837,6 @@ uint8_t pack_color_endpoints(
void unpack_color_endpoints(
astcenc_profile decode_mode,
int format,
quant_method quant_level,
const uint8_t* input,
bool& rgb_hdr,
bool& alpha_hdr,
@ -1894,13 +1908,13 @@ unsigned int compute_ideal_endpoint_formats(
* As we quantize and decimate weights the optimal endpoint colors may change slightly, so we must
* recompute the ideal colors for a specific weight set.
*
* @param blk The image block color data to compress.
* @param pi The partition info for the current trial.
* @param di The weight grid decimation table.
* @param blk The image block color data to compress.
* @param pi The partition info for the current trial.
* @param di The weight grid decimation table.
* @param dec_weights_uquant The quantized weight set.
* @param[in,out] ep The color endpoints (modifed in place).
* @param[out] rgbs_vectors The RGB+scale vectors for LDR blocks.
* @param[out] rgbo_vectors The RGB+offset vectors for HDR blocks.
* @param[in,out] ep The color endpoints (modifed in place).
* @param[out] rgbs_vectors The RGB+scale vectors for LDR blocks.
* @param[out] rgbo_vectors The RGB+offset vectors for HDR blocks.
*/
void recompute_ideal_colors_1plane(
const image_block& blk,
@ -1917,15 +1931,15 @@ void recompute_ideal_colors_1plane(
* As we quantize and decimate weights the optimal endpoint colors may change slightly, so we must
* recompute the ideal colors for a specific weight set.
*
* @param blk The image block color data to compress.
* @param bsd The block_size descriptor.
* @param di The weight grid decimation table.
* @param blk The image block color data to compress.
* @param bsd The block_size descriptor.
* @param di The weight grid decimation table.
* @param dec_weights_uquant_plane1 The quantized weight set for plane 1.
* @param dec_weights_uquant_plane2 The quantized weight set for plane 2.
* @param[in,out] ep The color endpoints (modifed in place).
* @param[out] rgbs_vector The RGB+scale color for LDR blocks.
* @param[out] rgbo_vector The RGB+offset color for HDR blocks.
* @param plane2_component The component assigned to plane 2.
* @param[in,out] ep The color endpoints (modifed in place).
* @param[out] rgbs_vector The RGB+scale color for LDR blocks.
* @param[out] rgbo_vector The RGB+offset color for HDR blocks.
* @param plane2_component The component assigned to plane 2.
*/
void recompute_ideal_colors_2planes(
const image_block& blk,
@ -1946,15 +1960,13 @@ void prepare_angular_tables();
/**
* @brief Compute the angular endpoints for one plane for each block mode.
*
* @param tune_low_weight_limit Weight count cutoff below which we use simpler searches.
* @param only_always Only consider block modes that are always enabled.
* @param bsd The block size descriptor for the current trial.
* @param dec_weight_ideal_value The ideal decimated unquantized weight values.
* @param max_weight_quant The maximum block mode weight quantization allowed.
* @param[out] tmpbuf Preallocated scratch buffers for the compressor.
* @param only_always Only consider block modes that are always enabled.
* @param bsd The block size descriptor for the current trial.
* @param dec_weight_ideal_value The ideal decimated unquantized weight values.
* @param max_weight_quant The maximum block mode weight quantization allowed.
* @param[out] tmpbuf Preallocated scratch buffers for the compressor.
*/
void compute_angular_endpoints_1plane(
unsigned int tune_low_weight_limit,
bool only_always,
const block_size_descriptor& bsd,
const float* dec_weight_ideal_value,
@ -1964,14 +1976,12 @@ void compute_angular_endpoints_1plane(
/**
* @brief Compute the angular endpoints for two planes for each block mode.
*
* @param tune_low_weight_limit Weight count cutoff below which we use simpler searches.
* @param bsd The block size descriptor for the current trial.
* @param dec_weight_ideal_value The ideal decimated unquantized weight values.
* @param max_weight_quant The maximum block mode weight quantization allowed.
* @param[out] tmpbuf Preallocated scratch buffers for the compressor.
* @param bsd The block size descriptor for the current trial.
* @param dec_weight_ideal_value The ideal decimated unquantized weight values.
* @param max_weight_quant The maximum block mode weight quantization allowed.
* @param[out] tmpbuf Preallocated scratch buffers for the compressor.
*/
void compute_angular_endpoints_2planes(
unsigned int tune_low_weight_limit,
const block_size_descriptor& bsd,
const float* dec_weight_ideal_value,
unsigned int max_weight_quant,
@ -2183,18 +2193,4 @@ void aligned_free(T* ptr)
#endif
}
static inline void dump_weights(const char* label, uint8_t* weights, int weight_count)
{
printf("%s\n", label);
vint lane = vint::lane_id();
for (int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH)
{
vmask mask = lane < vint(weight_count);
vint val(weights + i);
val = select(vint::zero(), val, mask);
print(val);
lane += vint(ASTCENC_SIMD_WIDTH);
}
}
#endif

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2011-2022 Arm Limited
// Copyright 2011-2023 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
@ -21,6 +21,9 @@
#include "astcenc_internal.h"
/** @brief The number of 64-bit words needed to represent a canonical partition bit pattern. */
#define BIT_PATTERN_WORDS (((ASTCENC_BLOCK_MAX_TEXELS * 2) + 63) / 64)
/**
* @brief Generate a canonical representation of a partition pattern.
*
@ -28,22 +31,22 @@
* the remapped texel index. Remapping ensures that we only match on the partition pattern,
* independent of the partition order generated by the hash.
*
* @param texel_count The number of texels in the block.
* @param partition_of_texel The partition assignments, in hash order.
* @param[out] bit_pattern The output bit pattern representation.
* @param texel_count The number of texels in the block.
* @param partition_of_texel The partition assignments, in hash order.
* @param[out] bit_pattern The output bit pattern representation.
*/
static void generate_canonical_partitioning(
unsigned int texel_count,
const uint8_t* partition_of_texel,
uint64_t bit_pattern[7]
uint64_t bit_pattern[BIT_PATTERN_WORDS]
) {
// Clear the pattern
for (unsigned int i = 0; i < 7; i++)
for (unsigned int i = 0; i < BIT_PATTERN_WORDS; i++)
{
bit_pattern[i] = 0;
}
// Store a mapping to reorder the raw partitions so that the the partitions are ordered such
// Store a mapping to reorder the raw partitions so that the partitions are ordered such
// that the lowest texel index in partition N is smaller than the lowest texel index in
// partition N + 1.
int mapped_index[BLOCK_MAX_PARTITIONS];
@ -76,19 +79,35 @@ static void generate_canonical_partitioning(
* @return @c true if the patterns are the same, @c false otherwise.
*/
static bool compare_canonical_partitionings(
const uint64_t part1[7],
const uint64_t part2[7]
const uint64_t part1[BIT_PATTERN_WORDS],
const uint64_t part2[BIT_PATTERN_WORDS]
) {
return (part1[0] == part2[0]) && (part1[1] == part2[1]) &&
(part1[2] == part2[2]) && (part1[3] == part2[3]) &&
(part1[4] == part2[4]) && (part1[5] == part2[5]) &&
(part1[6] == part2[6]);
return (part1[0] == part2[0])
#if BIT_PATTERN_WORDS > 1
&& (part1[1] == part2[1])
#endif
#if BIT_PATTERN_WORDS > 2
&& (part1[2] == part2[2])
#endif
#if BIT_PATTERN_WORDS > 3
&& (part1[3] == part2[3])
#endif
#if BIT_PATTERN_WORDS > 4
&& (part1[4] == part2[4])
#endif
#if BIT_PATTERN_WORDS > 5
&& (part1[5] == part2[5])
#endif
#if BIT_PATTERN_WORDS > 6
&& (part1[6] == part2[6])
#endif
;
}
/**
* @brief Hash function used for procedural partition assignment.
*
* @param inp The hash seed.
* @param inp The hash seed.
*
* @return The hashed value.
*/
@ -116,7 +135,7 @@ static uint32_t hash52(
* @param y The texel Y coordinate in the block.
* @param z The texel Z coordinate in the block.
* @param partition_count The total partition count of this encoding.
* @param small_block @c true if the blockhas fewer than 32 texels.
* @param small_block @c true if the block has fewer than 32 texels.
*
* @return The assigned partition index for this texel.
*/
@ -320,21 +339,17 @@ static bool generate_one_partition_info_entry(
// Populate the coverage bitmaps for 2/3/4 partitions
uint64_t* bitmaps { nullptr };
uint8_t* valids { nullptr };
if (partition_count == 2)
{
bitmaps = bsd.coverage_bitmaps_2[partition_remap_index];
valids = bsd.partitioning_valid_2;
}
else if (partition_count == 3)
{
bitmaps = bsd.coverage_bitmaps_3[partition_remap_index];
valids = bsd.partitioning_valid_3;
}
else if (partition_count == 4)
{
bitmaps = bsd.coverage_bitmaps_4[partition_remap_index];
valids = bsd.partitioning_valid_4;
}
for (unsigned int i = 0; i < BLOCK_MAX_PARTITIONS; i++)
@ -347,9 +362,7 @@ static bool generate_one_partition_info_entry(
if (bitmaps)
{
// Populate the bitmap validity mask
valids[partition_remap_index] = valid ? 0 : 255;
// Populate the partition coverage bitmap
for (unsigned int i = 0; i < partition_count; i++)
{
bitmaps[i] = 0ULL;
@ -374,12 +387,6 @@ static void build_partition_table_for_one_partition_count(
partition_info* ptab,
uint64_t* canonical_patterns
) {
uint8_t* partitioning_valid[3] {
bsd.partitioning_valid_2,
bsd.partitioning_valid_3,
bsd.partitioning_valid_4
};
unsigned int next_index = 0;
bsd.partitioning_count_selected[partition_count - 1] = 0;
bsd.partitioning_count_all[partition_count - 1] = 0;
@ -397,7 +404,7 @@ static void build_partition_table_for_one_partition_count(
// Tracker for things we built in the first iteration
uint8_t build[BLOCK_MAX_PARTITIONINGS] { 0 };
for (unsigned int x = 0; x < max_iter; x++)
for (unsigned int x = 0; x < max_iter; x++)
{
for (unsigned int i = 0; i < BLOCK_MAX_PARTITIONINGS; i++)
{
@ -413,11 +420,11 @@ static void build_partition_table_for_one_partition_count(
continue;
}
generate_canonical_partitioning(bsd.texel_count, ptab[next_index].partition_of_texel, canonical_patterns + next_index * 7);
generate_canonical_partitioning(bsd.texel_count, ptab[next_index].partition_of_texel, canonical_patterns + next_index * BIT_PATTERN_WORDS);
bool keep_canonical = true;
for (unsigned int j = 0; j < next_index; j++)
{
bool match = compare_canonical_partitionings(canonical_patterns + 7 * next_index, canonical_patterns + 7 * j);
bool match = compare_canonical_partitionings(canonical_patterns + next_index * BIT_PATTERN_WORDS, canonical_patterns + j * BIT_PATTERN_WORDS);
if (match)
{
keep_canonical = false;
@ -442,7 +449,6 @@ static void build_partition_table_for_one_partition_count(
{
bsd.partitioning_packed_index[partition_count - 2][i] = static_cast<uint16_t>(next_index);
bsd.partitioning_count_all[partition_count - 1]++;
partitioning_valid[partition_count - 2][next_index] = 255;
next_index++;
}
}
@ -465,7 +471,8 @@ void init_partition_tables(
bsd.partitioning_count_selected[0] = 1;
bsd.partitioning_count_all[0] = 1;
uint64_t* canonical_patterns = new uint64_t[BLOCK_MAX_PARTITIONINGS * 7];
uint64_t* canonical_patterns = new uint64_t[BLOCK_MAX_PARTITIONINGS * BIT_PATTERN_WORDS];
build_partition_table_for_one_partition_count(bsd, can_omit_partitionings, partition_count_cutoff, 2, par_tab2, canonical_patterns);
build_partition_table_for_one_partition_count(bsd, can_omit_partitionings, partition_count_cutoff, 3, par_tab3, canonical_patterns);
build_partition_table_for_one_partition_count(bsd, can_omit_partitionings, partition_count_cutoff, 4, par_tab4, canonical_patterns);

View File

@ -1166,11 +1166,11 @@ const float *get_2d_percentile_table(
unsigned int xdim,
unsigned int ydim
) {
float* unpacked_table = new float[2048];
float* unpacked_table = new float[WEIGHTS_MAX_BLOCK_MODES];
const packed_percentile_table *apt = get_packed_table(xdim, ydim);
// Set the default percentile
for (unsigned int i = 0; i < 2048; i++)
for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++)
{
unpacked_table[i] = 1.0f;
}

View File

@ -325,11 +325,7 @@ static void compute_color_error_for_every_integer_count_and_quant_level(
) {
int partition_size = pi.partition_texel_count[partition_index];
static const float baseline_quant_error[21] {
(65536.0f * 65536.0f / 18.0f), // 2 values, 1 step
(65536.0f * 65536.0f / 18.0f) / (2 * 2), // 3 values, 2 steps
(65536.0f * 65536.0f / 18.0f) / (3 * 3), // 4 values, 3 steps
(65536.0f * 65536.0f / 18.0f) / (4 * 4), // 5 values
static const float baseline_quant_error[21 - QUANT_6] {
(65536.0f * 65536.0f / 18.0f) / (5 * 5),
(65536.0f * 65536.0f / 18.0f) / (7 * 7),
(65536.0f * 65536.0f / 18.0f) / (9 * 9),
@ -528,7 +524,7 @@ static void compute_color_error_for_every_integer_count_and_quant_level(
// The base_quant_error should depend on the scale-factor that would be used during
// actual encode of the color value
float base_quant_error = baseline_quant_error[i] * static_cast<float>(partition_size);
float base_quant_error = baseline_quant_error[i - QUANT_6] * static_cast<float>(partition_size);
float rgb_quantization_error = error_weight_rgbsum * base_quant_error * 2.0f;
float alpha_quantization_error = error_weight.lane<3>() * base_quant_error * 2.0f;
float rgba_quantization_error = rgb_quantization_error + alpha_quantization_error;
@ -591,7 +587,7 @@ static void compute_color_error_for_every_integer_count_and_quant_level(
error_scale_oe_rgb = 1.0f;
}
float base_quant_error = baseline_quant_error[i];
float base_quant_error = baseline_quant_error[i - QUANT_6];
float quant_error_rgb = base_quant_error_rgb * base_quant_error;
float quant_error_rgba = base_quant_error_rgba * base_quant_error;
@ -1136,22 +1132,19 @@ unsigned int compute_ideal_endpoint_formats(
uint8_t (&best_ep_formats)[WEIGHTS_MAX_BLOCK_MODES][BLOCK_MAX_PARTITIONS] = tmpbuf.best_ep_formats;
// Ensure that the first iteration understep contains data that will never be picked
vfloat clear_error(ERROR_CALC_DEFAULT);
vint clear_quant(0);
unsigned int packed_start_block_mode = round_down_to_simd_multiple_vla(start_block_mode);
for (unsigned int i = packed_start_block_mode; i < start_block_mode; i++)
{
errors_of_best_combination[i] = ERROR_CALC_DEFAULT;
best_quant_levels[i] = QUANT_2;
best_quant_levels_mod[i] = QUANT_2;
}
storea(clear_error, errors_of_best_combination + packed_start_block_mode);
store_nbytes(clear_quant, best_quant_levels + packed_start_block_mode);
store_nbytes(clear_quant, best_quant_levels_mod + packed_start_block_mode);
// Ensure that last iteration overstep contains data that will never be picked
const unsigned int packed_end_block_mode = round_up_to_simd_multiple_vla(end_block_mode);
for (unsigned int i = end_block_mode; i < packed_end_block_mode; i++)
{
errors_of_best_combination[i] = ERROR_CALC_DEFAULT;
best_quant_levels[i] = QUANT_2;
best_quant_levels_mod[i] = QUANT_2;
}
unsigned int packed_end_block_mode = round_down_to_simd_multiple_vla(end_block_mode - 1);
storea(clear_error, errors_of_best_combination + packed_end_block_mode);
store_nbytes(clear_quant, best_quant_levels + packed_end_block_mode);
store_nbytes(clear_quant, best_quant_levels_mod + packed_end_block_mode);
// Track a scalar best to avoid expensive search at least once ...
float error_of_best_combination = ERROR_CALC_DEFAULT;
@ -1160,7 +1153,7 @@ unsigned int compute_ideal_endpoint_formats(
// The block contains 1 partition
if (partition_count == 1)
{
for (unsigned int i = start_block_mode; i < end_block_mode; ++i)
for (unsigned int i = start_block_mode; i < end_block_mode; i++)
{
if (qwt_errors[i] >= ERROR_CALC_DEFAULT)
{
@ -1193,7 +1186,7 @@ unsigned int compute_ideal_endpoint_formats(
best_error, format_of_choice, combined_best_error, formats_of_choice);
assert(start_block_mode == 0);
for (unsigned int i = 0; i < end_block_mode; ++i)
for (unsigned int i = 0; i < end_block_mode; i++)
{
if (qwt_errors[i] >= ERROR_CALC_DEFAULT)
{
@ -1226,7 +1219,7 @@ unsigned int compute_ideal_endpoint_formats(
best_error, format_of_choice, combined_best_error, formats_of_choice);
assert(start_block_mode == 0);
for (unsigned int i = 0; i < end_block_mode; ++i)
for (unsigned int i = 0; i < end_block_mode; i++)
{
if (qwt_errors[i] >= ERROR_CALC_DEFAULT)
{
@ -1260,7 +1253,7 @@ unsigned int compute_ideal_endpoint_formats(
best_error, format_of_choice, combined_best_error, formats_of_choice);
assert(start_block_mode == 0);
for (unsigned int i = 0; i < end_block_mode; ++i)
for (unsigned int i = 0; i < end_block_mode; i++)
{
if (qwt_errors[i] >= ERROR_CALC_DEFAULT)
{

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// ----------------------------------------------------------------------------
// Copyright 2020-2021 Arm Limited
// Copyright 2020-2022 Arm Limited
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
@ -47,7 +47,7 @@ static bool g_cpu_has_f16c { false };
============================================================================ */
#if !defined(__clang__) && defined(_MSC_VER)
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <windows.h>
#include <intrin.h>
/**

File diff suppressed because it is too large Load Diff

View File

@ -265,13 +265,15 @@ void symbolic_to_physical(
// Encode the color components
uint8_t values_to_encode[32];
int valuecount_to_encode = 0;
const uint8_t* pack_table = color_uquant_to_scrambled_pquant_tables[scb.quant_mode - QUANT_6];
for (unsigned int i = 0; i < scb.partition_count; i++)
{
int vals = 2 * (scb.color_formats[i] >> 2) + 2;
assert(vals <= 8);
for (int j = 0; j < vals; j++)
{
values_to_encode[j + valuecount_to_encode] = scb.color_values[i][j];
values_to_encode[j + valuecount_to_encode] = pack_table[scb.color_values[i][j]];
}
valuecount_to_encode += vals;
}
@ -369,12 +371,15 @@ void physical_to_symbolic(
const auto& di = bsd.get_decimation_info(bm.decimation_mode);
int weight_count = di.weight_count;
promise(weight_count > 0);
quant_method weight_quant_method = static_cast<quant_method>(bm.quant_mode);
int is_dual_plane = bm.is_dual_plane;
int real_weight_count = is_dual_plane ? 2 * weight_count : weight_count;
int partition_count = read_bits(2, 11, pcb.data) + 1;
promise(partition_count > 0);
scb.block_mode = static_cast<uint16_t>(block_mode);
scb.partition_count = static_cast<uint8_t>(partition_count);
@ -503,22 +508,25 @@ void physical_to_symbolic(
// Unpack the integer color values and assign to endpoints
scb.quant_mode = static_cast<quant_method>(color_quant_level);
uint8_t values_to_decode[32];
decode_ise(static_cast<quant_method>(color_quant_level), color_integer_count, pcb.data,
values_to_decode, (partition_count == 1 ? 17 : 19 + PARTITION_INDEX_BITS));
int valuecount_to_decode = 0;
const uint8_t* unpack_table = color_scrambled_pquant_to_uquant_tables[scb.quant_mode - QUANT_6];
for (int i = 0; i < partition_count; i++)
{
int vals = 2 * (color_formats[i] >> 2) + 2;
for (int j = 0; j < vals; j++)
{
scb.color_values[i][j] = values_to_decode[j + valuecount_to_decode];
scb.color_values[i][j] = unpack_table[values_to_decode[j + valuecount_to_decode]];
}
valuecount_to_decode += vals;
}
// Fetch component for second-plane in the case of dual plane of weights.
scb.plane2_component = -1;
if (is_dual_plane)
{
scb.plane2_component = static_cast<int8_t>(read_bits(2, below_weights_pos - 2, pcb.data));

View File

@ -26,7 +26,7 @@
* with that is available at compile time. The current vector width is
* accessible for e.g. loop strides via the ASTCENC_SIMD_WIDTH constant.
*
* Explicit scalar types are acessible via the vint1, vfloat1, vmask1 types.
* Explicit scalar types are accessible via the vint1, vfloat1, vmask1 types.
* These are provided primarily for prototyping and algorithm debug of VLA
* implementations.
*
@ -402,7 +402,7 @@ static ASTCENC_SIMD_INLINE vint4 clz(vint4 a)
// the original integer value into a 2^N encoding we can recover easily.
// Convert to float without risk of rounding up by keeping only top 8 bits.
// This trick is is guranteed to keep top 8 bits and clear the 9th.
// This trick is is guaranteed to keep top 8 bits and clear the 9th.
a = (~lsr<8>(a)) & a;
a = float_as_int(int_to_float(a));
@ -416,7 +416,7 @@ static ASTCENC_SIMD_INLINE vint4 clz(vint4 a)
/**
* @brief Return lanewise 2^a for each lane in @c a.
*
* Use of signed int mean that this is only valid for values in range [0, 31].
* Use of signed int means that this is only valid for values in range [0, 31].
*/
static ASTCENC_SIMD_INLINE vint4 two_to_the_n(vint4 a)
{

View File

@ -89,7 +89,8 @@ struct vfloat8
/**
* @brief Construct from an existing SIMD register.
*/
ASTCENC_SIMD_INLINE explicit vfloat8(__m256 a) {
ASTCENC_SIMD_INLINE explicit vfloat8(__m256 a)
{
m = a;
}

View File

@ -361,6 +361,23 @@ static inline int popcount(uint64_t v)
#endif
/**
* @brief Apply signed bit transfer.
*
* @param input0 The first encoded endpoint.
* @param input1 The second encoded endpoint.
*/
static ASTCENC_SIMD_INLINE void bit_transfer_signed(
vint4& input0,
vint4& input1
) {
input1 = lsr<1>(input1) | (input0 & 0x80);
input0 = lsr<1>(input0) & 0x3F;
vmask4 mask = (input0 & 0x20) != vint4::zero();
input0 = select(input0, input0 - 0x40, mask);
}
/**
* @brief Debug function to print a vector of ints.
*/

View File

@ -106,7 +106,7 @@ struct vfloat4
*/
template <int l> ASTCENC_SIMD_INLINE void set_lane(float a)
{
m = vld1q_lane_f32(&a, m, l);
m = vsetq_lane_f32(a, m, l);
}
/**
@ -122,7 +122,7 @@ struct vfloat4
*/
static ASTCENC_SIMD_INLINE vfloat4 load1(const float* p)
{
return vfloat4(vdupq_n_f32(*p));
return vfloat4(vld1q_dup_f32(p));
}
/**
@ -202,9 +202,8 @@ struct vint4
*/
ASTCENC_SIMD_INLINE explicit vint4(const uint8_t *p)
{
uint32x2_t t8 {};
// Cast is safe - NEON loads are allowed to be unaligned
t8 = vld1_lane_u32(reinterpret_cast<const uint32_t*>(p), t8, 0);
uint32x2_t t8 = vld1_dup_u32(reinterpret_cast<const uint32_t*>(p));
uint16x4_t t16 = vget_low_u16(vmovl_u8(vreinterpret_u8_u32(t8)));
m = vreinterpretq_s32_u32(vmovl_u16(t16));
}
@ -251,7 +250,7 @@ struct vint4
*/
template <int l> ASTCENC_SIMD_INLINE void set_lane(int a)
{
m = vld1q_lane_s32(&a, m, l);
m = vsetq_lane_s32(a, m, l);
}
/**
@ -1039,18 +1038,18 @@ ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint4 data, vmask4 mask)
{
store(data, base);
}
else if(mask.lane<2>())
else if (mask.lane<2>())
{
base[0] = data.lane<0>();
base[1] = data.lane<1>();
base[2] = data.lane<2>();
}
else if(mask.lane<1>())
else if (mask.lane<1>())
{
base[0] = data.lane<0>();
base[1] = data.lane<1>();
}
else if(mask.lane<0>())
else if (mask.lane<0>())
{
base[0] = data.lane<0>();
}

View File

@ -1149,18 +1149,18 @@ ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint4 data, vmask4 mask)
{
store(data, base);
}
else if(mask.m[2])
else if (mask.m[2])
{
base[0] = data.lane<0>();
base[1] = data.lane<1>();
base[2] = data.lane<2>();
}
else if(mask.m[1])
else if (mask.m[1])
{
base[0] = data.lane<0>();
base[1] = data.lane<1>();
}
else if(mask.m[0])
else if (mask.m[0])
{
base[0] = data.lane<0>();
}

View File

@ -1206,18 +1206,18 @@ ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint4 data, vmask4 mask)
{
store(data, base);
}
else if(mask.lane<2>() != 0.0f)
else if (mask.lane<2>() != 0.0f)
{
base[0] = data.lane<0>();
base[1] = data.lane<1>();
base[2] = data.lane<2>();
}
else if(mask.lane<1>() != 0.0f)
else if (mask.lane<1>() != 0.0f)
{
base[0] = data.lane<0>();
base[1] = data.lane<1>();
}
else if(mask.lane<0>() != 0.0f)
else if (mask.lane<0>() != 0.0f)
{
base[0] = data.lane<0>();
}

View File

@ -176,7 +176,7 @@ static void compute_lowest_and_highest_weight(
vfloat cut_high_weight_err = vfloat::zero();
vfloat offset = loada(offsets + sp);
for (unsigned int j = 0; j < weight_count; ++j)
for (unsigned int j = 0; j < weight_count; j++)
{
vfloat sval = load1(dec_weight_ideal_value + j) * rcp_stepsize - offset;
vfloat svalrte = round(sval);
@ -287,25 +287,25 @@ static void compute_angular_endpoints_for_quant_levels(
// Check best error against record N
vfloat4 best_result = best_results[idx_span];
vfloat4 new_result = vfloat4(error[i], i_flt, 0.0f, 0.0f);
vmask4 mask1(best_result.lane<0>() > error[i]);
best_results[idx_span] = select(best_result, new_result, mask1);
vmask4 mask = vfloat4(best_result.lane<0>()) > vfloat4(error[i]);
best_results[idx_span] = select(best_result, new_result, mask);
// Check best error against record N-1 with either cut low or cut high
best_result = best_results[idx_span - 1];
new_result = vfloat4(error_cut_low, i_flt, 1.0f, 0.0f);
vmask4 mask2(best_result.lane<0>() > error_cut_low);
best_result = select(best_result, new_result, mask2);
mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_low);
best_result = select(best_result, new_result, mask);
new_result = vfloat4(error_cut_high, i_flt, 0.0f, 0.0f);
vmask4 mask3(best_result.lane<0>() > error_cut_high);
best_results[idx_span - 1] = select(best_result, new_result, mask3);
mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_high);
best_results[idx_span - 1] = select(best_result, new_result, mask);
// Check best error against record N-2 with both cut low and high
best_result = best_results[idx_span - 2];
new_result = vfloat4(error_cut_low_high, i_flt, 1.0f, 0.0f);
vmask4 mask4(best_result.lane<0>() > error_cut_low_high);
best_results[idx_span - 2] = select(best_result, new_result, mask4);
mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_low_high);
best_results[idx_span - 2] = select(best_result, new_result, mask);
}
for (unsigned int i = 0; i <= max_quant_level; i++)
@ -333,158 +333,8 @@ static void compute_angular_endpoints_for_quant_levels(
}
}
/**
* @brief For a given step size compute the lowest and highest weight, variant for low weight count.
*
* Compute the lowest and highest weight that results from quantizing using the given stepsize and
* offset, and then compute the resulting error. The cut errors indicate the error that results from
* forcing samples that should have had one weight value one step up or down.
*
* @param weight_count The number of (decimated) weights.
* @param dec_weight_quant_uvalue The decimated and quantized weight values.
* @param max_angular_steps The maximum number of steps to be tested.
* @param max_quant_steps The maximum quantization level to be tested.
* @param offsets The angular offsets array.
* @param[out] lowest_weight Per angular step, the lowest weight.
* @param[out] weight_span Per angular step, the span between lowest and highest weight.
* @param[out] error Per angular step, the error.
*/
static void compute_lowest_and_highest_weight_lwc(
unsigned int weight_count,
const float* dec_weight_quant_uvalue,
unsigned int max_angular_steps,
unsigned int max_quant_steps,
const float* offsets,
float* lowest_weight,
int* weight_span,
float* error
) {
promise(weight_count > 0);
promise(max_angular_steps > 0);
vfloat rcp_stepsize = vfloat::lane_id() + vfloat(1.0f);
// Arrays are ANGULAR_STEPS long, so always safe to run full vectors
for (unsigned int sp = 0; sp < max_angular_steps; sp += ASTCENC_SIMD_WIDTH)
{
vfloat minidx(128.0f);
vfloat maxidx(-128.0f);
vfloat errval = vfloat::zero();
vfloat offset = loada(offsets + sp);
for (unsigned int j = 0; j < weight_count; ++j)
{
vfloat sval = load1(dec_weight_quant_uvalue + j) * rcp_stepsize - offset;
vfloat svalrte = round(sval);
vfloat diff = sval - svalrte;
errval += diff * diff;
// Compute min and max quantized weight spans for each step
minidx = min(minidx, svalrte);
maxidx = max(maxidx, svalrte);
}
// Write out min weight and weight span; clamp span to a usable range
vint span = float_to_int(maxidx - minidx + vfloat(1.0f));
span = min(span, vint(max_quant_steps + 3));
span = max(span, vint(2));
storea(minidx, lowest_weight + sp);
storea(span, weight_span + sp);
// The cut_(lowest/highest)_weight_error indicate the error that results from
// forcing samples that should have had the weight value one step (up/down).
vfloat ssize = 1.0f / rcp_stepsize;
vfloat errscale = ssize * ssize;
storea(errval * errscale, error + sp);
rcp_stepsize = rcp_stepsize + vfloat(ASTCENC_SIMD_WIDTH);
}
}
/**
* @brief The main function for the angular algorithm, variant for low weight count.
*
* @param weight_count The number of (decimated) weights.
* @param dec_weight_ideal_value The ideal decimated unquantized weight values.
* @param max_quant_level The maximum quantization level to be tested.
* @param[out] low_value Per angular step, the lowest weight value.
* @param[out] high_value Per angular step, the highest weight value.
*/
static void compute_angular_endpoints_for_quant_levels_lwc(
unsigned int weight_count,
const float* dec_weight_ideal_value,
unsigned int max_quant_level,
float low_value[TUNE_MAX_ANGULAR_QUANT + 1],
float high_value[TUNE_MAX_ANGULAR_QUANT + 1]
) {
unsigned int max_quant_steps = steps_for_quant_level[max_quant_level];
unsigned int max_angular_steps = steps_for_quant_level[max_quant_level];
alignas(ASTCENC_VECALIGN) float angular_offsets[ANGULAR_STEPS];
alignas(ASTCENC_VECALIGN) float lowest_weight[ANGULAR_STEPS];
alignas(ASTCENC_VECALIGN) int32_t weight_span[ANGULAR_STEPS];
alignas(ASTCENC_VECALIGN) float error[ANGULAR_STEPS];
compute_angular_offsets(weight_count, dec_weight_ideal_value,
max_angular_steps, angular_offsets);
compute_lowest_and_highest_weight_lwc(weight_count, dec_weight_ideal_value,
max_angular_steps, max_quant_steps,
angular_offsets, lowest_weight, weight_span, error);
// For each quantization level, find the best error terms. Use packed vectors so data-dependent
// branches can become selects. This involves some integer to float casts, but the values are
// small enough so they never round the wrong way.
vfloat4 best_results[36];
// Initialize the array to some safe defaults
promise(max_quant_steps > 0);
for (unsigned int i = 0; i < (max_quant_steps + 4); i++)
{
best_results[i] = vfloat4(ERROR_CALC_DEFAULT, -1.0f, 0.0f, 0.0f);
}
promise(max_angular_steps > 0);
for (unsigned int i = 0; i < max_angular_steps; i++)
{
int idx_span = weight_span[i];
// Check best error against record N
vfloat4 current_best = best_results[idx_span];
vfloat4 candidate = vfloat4(error[i], static_cast<float>(i), 0.0f, 0.0f);
vmask4 mask(current_best.lane<0>() > error[i]);
best_results[idx_span] = select(current_best, candidate, mask);
}
for (unsigned int i = 0; i <= max_quant_level; i++)
{
unsigned int q = steps_for_quant_level[i];
int bsi = static_cast<int>(best_results[q].lane<1>());
// Did we find anything?
#if defined(ASTCENC_DIAGNOSTICS)
if ((bsi < 0) && print_once)
{
print_once = false;
printf("INFO: Unable to find low weight encoding within search error limit.\n\n");
}
#endif
bsi = astc::max(0, bsi);
float lwi = lowest_weight[bsi];
float hwi = lwi + static_cast<float>(q) - 1.0f;
float stepsize = 1.0f / (1.0f + static_cast<float>(bsi));
low_value[i] = (angular_offsets[bsi] + lwi) * stepsize;
high_value[i] = (angular_offsets[bsi] + hwi) * stepsize;
}
}
/* See header for documentation. */
void compute_angular_endpoints_1plane(
unsigned int tune_low_weight_limit,
bool only_always,
const block_size_descriptor& bsd,
const float* dec_weight_ideal_value,
@ -521,26 +371,16 @@ void compute_angular_endpoints_1plane(
max_precision = max_weight_quant;
}
if (weight_count < tune_low_weight_limit)
{
compute_angular_endpoints_for_quant_levels_lwc(
weight_count,
dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS,
max_precision, low_values[i], high_values[i]);
}
else
{
compute_angular_endpoints_for_quant_levels(
weight_count,
dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS,
max_precision, low_values[i], high_values[i]);
}
compute_angular_endpoints_for_quant_levels(
weight_count,
dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS,
max_precision, low_values[i], high_values[i]);
}
unsigned int max_block_modes = only_always ? bsd.block_mode_count_1plane_always
: bsd.block_mode_count_1plane_selected;
promise(max_block_modes > 0);
for (unsigned int i = 0; i < max_block_modes; ++i)
for (unsigned int i = 0; i < max_block_modes; i++)
{
const block_mode& bm = bsd.block_modes[i];
assert(!bm.is_dual_plane);
@ -563,7 +403,6 @@ void compute_angular_endpoints_1plane(
/* See header for documentation. */
void compute_angular_endpoints_2planes(
unsigned int tune_low_weight_limit,
const block_size_descriptor& bsd,
const float* dec_weight_ideal_value,
unsigned int max_weight_quant,
@ -601,30 +440,15 @@ void compute_angular_endpoints_2planes(
max_precision = max_weight_quant;
}
if (weight_count < tune_low_weight_limit)
{
compute_angular_endpoints_for_quant_levels_lwc(
weight_count,
dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS,
max_precision, low_values1[i], high_values1[i]);
compute_angular_endpoints_for_quant_levels(
weight_count,
dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS,
max_precision, low_values1[i], high_values1[i]);
compute_angular_endpoints_for_quant_levels_lwc(
weight_count,
dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS + WEIGHTS_PLANE2_OFFSET,
max_precision, low_values2[i], high_values2[i]);
}
else
{
compute_angular_endpoints_for_quant_levels(
weight_count,
dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS,
max_precision, low_values1[i], high_values1[i]);
compute_angular_endpoints_for_quant_levels(
weight_count,
dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS + WEIGHTS_PLANE2_OFFSET,
max_precision, low_values2[i], high_values2[i]);
}
compute_angular_endpoints_for_quant_levels(
weight_count,
dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS + WEIGHTS_PLANE2_OFFSET,
max_precision, low_values2[i], high_values2[i]);
}
unsigned int start = bsd.block_mode_count_1plane_selected;

View File

@ -24,9 +24,8 @@
#define _ 0 // Using _ to indicate an entry that will not be used.
const quant_and_transfer_table quant_and_xfer_tables[12] {
// Quantization method 0, range 0..1
// QUANT2, range 0..1
{
QUANT_2,
{0, 64},
{0, 1},
{0, 64},
@ -34,9 +33,8 @@ const quant_and_transfer_table quant_and_xfer_tables[12] {
_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,
0x4000}
},
// Quantization method 1, range 0..2
// QUANT_3, range 0..2
{
QUANT_3,
{0, 32, 64},
{0, 1, 2},
{0, 32, 64},
@ -44,19 +42,17 @@ const quant_and_transfer_table quant_and_xfer_tables[12] {
_,_,0x4000,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,
_,_,_,_,0x4020}
},
// Quantization method 2, range 0..3
// QUANT_4, range 0..3
{
QUANT_4,
{0, 21, 43, 64},
{0, 1, 2, 3},
{0, 21, 43, 64},
{0, 21, 43, 64},
{0x1500,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x2b00,_,_,_,_,
_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x4015,_,_,_,_,_,_,_,_,_,_,_,_,
_,_,_,_,_,_,_,_,0x402b}
},
// Quantization method 3, range 0..4
//QUANT_5, range 0..4
{
QUANT_5,
{0, 16, 32, 48, 64},
{0, 1, 2, 3, 4},
{0, 16, 32, 48, 64},
@ -64,9 +60,8 @@ const quant_and_transfer_table quant_and_xfer_tables[12] {
_,_,_,_,_,_,0x3010,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x4020,_,_,_,
_,_,_,_,_,_,_,_,_,_,_,_,0x4030}
},
// Quantization method 4, range 0..5
// QUANT_6, range 0..5
{
QUANT_6,
{0, 12, 25, 39, 52, 64},
{0, 2, 4, 5, 3, 1},
{0, 64, 12, 52, 25, 39},
@ -74,9 +69,8 @@ const quant_and_transfer_table quant_and_xfer_tables[12] {
0x270c,_,_,_,_,_,_,_,_,_,_,_,_,_,0x3419,_,_,_,_,_,_,_,_,_,_,
_,_,0x4027,_,_,_,_,_,_,_,_,_,_,_,0x4034}
},
// Quantization method 5, range 0..7
// QUANT_8, range 0..7
{
QUANT_8,
{0, 9, 18, 27, 37, 46, 55, 64},
{0, 1, 2, 3, 4, 5, 6, 7},
{0, 9, 18, 27, 37, 46, 55, 64},
@ -84,9 +78,8 @@ const quant_and_transfer_table quant_and_xfer_tables[12] {
_,_,_,_,_,_,0x2512,_,_,_,_,_,_,_,_,_,0x2e1b,_,_,_,_,_,_,_,_,
0x3725,_,_,_,_,_,_,_,_,0x402e,_,_,_,_,_,_,_,_,0x4037}
},
// Quantization method 6, range 0..9
// QUANT_10, range 0..9
{
QUANT_10,
{0, 7, 14, 21, 28, 36, 43, 50, 57, 64},
{0, 2, 4, 6, 8, 9, 7, 5, 3, 1},
{0, 64, 7, 57, 14, 50, 21, 43, 28, 36},
@ -95,9 +88,8 @@ const quant_and_transfer_table quant_and_xfer_tables[12] {
_,0x3224,_,_,_,_,_,_,0x392b,_,_,_,_,_,_,0x4032,_,_,_,_,_,
_,0x4039}
},
// Quantization method 7, range 0..11
// QUANT_12, range 0..11
{
QUANT_12,
{0, 5, 11, 17, 23, 28, 36, 41, 47, 53, 59, 64},
{0, 4, 8, 2, 6, 10, 11, 7, 3, 9, 5, 1},
{0, 64, 17, 47, 5, 59, 23, 41, 11, 53, 28, 36},
@ -106,9 +98,8 @@ const quant_and_transfer_table quant_and_xfer_tables[12] {
0x291c,_,_,_,_,0x2f24,_,_,_,_,_,0x3529,_,_,_,_,_,
0x3b2f,_,_,_,_,_,0x4035,_,_,_,_,0x403b}
},
// Quantization method 8, range 0..15
// QUANT_16, range 0..15
{
QUANT_16,
{0, 4, 8, 12, 17, 21, 25, 29, 35, 39, 43, 47, 52, 56, 60, 64},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
{0, 4, 8, 12, 17, 21, 25, 29, 35, 39, 43, 47, 52, 56, 60, 64},
@ -117,9 +108,8 @@ const quant_and_transfer_table quant_and_xfer_tables[12] {
_,0x271d,_,_,_,0x2b23,_,_,_,0x2f27,_,_,_,0x342b,_,_,_,
_,0x382f,_,_,_,0x3c34,_,_,_,0x4038,_,_,_,0x403c}
},
// Quantization method 9, range 0..19
// QUANT_20, range 0..19
{
QUANT_20,
{0, 3, 6, 9, 13, 16, 19, 23, 26, 29, 35, 38, 41, 45, 48, 51, 55, 58, 61, 64},
{0, 4, 8, 12, 16, 2, 6, 10, 14, 18, 19, 15, 11, 7, 3, 17, 13, 9, 5, 1},
{0, 64, 16, 48, 3, 61, 19, 45, 6, 58, 23, 41, 9, 55, 26, 38, 13, 51, 29, 35},
@ -129,9 +119,8 @@ const quant_and_transfer_table quant_and_xfer_tables[12] {
0x2d26,_,_,_,0x3029,_,_,0x332d,_,_,0x3730,_,_,_,
0x3a33,_,_,0x3d37,_,_,0x403a,_,_,0x403d}
},
// Quantization method 10, range 0..23
// QUANT_24, range 0..23
{
QUANT_24,
{0, 2, 5, 8, 11, 13, 16, 19, 22, 24, 27, 30, 34, 37, 40, 42, 45, 48, 51, 53, 56, 59, 62, 64},
{0, 8, 16, 2, 10, 18, 4, 12, 20, 6, 14, 22, 23, 15, 7, 21, 13, 5, 19, 11, 3, 17, 9, 1},
{0, 64, 8, 56, 16, 48, 24, 40, 2, 62, 11, 53, 19, 45, 27, 37, 5, 59, 13, 51, 22, 42, 30, 34},
@ -142,9 +131,8 @@ const quant_and_transfer_table quant_and_xfer_tables[12] {
_,_,0x3530,_,0x3833,_,_,0x3b35,_,_,0x3e38,_,_,
0x403b,_,0x403e}
},
// Quantization method 11, range 0..31
// QUANT_32, range 0..31
{
QUANT_32,
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64},

View File

@ -1,5 +1,5 @@
/**
* Loader generated by glad 2.0.2 on Thu Nov 10 09:27:21 2022
* Loader generated by glad 2.0.3 on Fri Jan 20 03:41:44 2023
*
* SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
*
@ -177,7 +177,7 @@ extern "C" {
#define GLAD_VERSION_MAJOR(version) (version / 10000)
#define GLAD_VERSION_MINOR(version) (version % 10000)
#define GLAD_GENERATOR_VERSION "2.0.2"
#define GLAD_GENERATOR_VERSION "2.0.3"
typedef void (*GLADapiproc)(void);
@ -10603,7 +10603,7 @@ typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DOESPROC)(GLenum target, GLint
typedef void (GLAD_API_PTR *PFNGLCOPYTEXTURELEVELSAPPLEPROC)(GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount);
typedef void (GLAD_API_PTR *PFNGLCOVERAGEMASKNVPROC)(GLboolean mask);
typedef void (GLAD_API_PTR *PFNGLCOVERAGEOPERATIONNVPROC)(GLenum operation);
typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROGRAMVEXTPROC)(GLenum type, GLsizei count, const GLchar ** strings);
typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROGRAMVEXTPROC)(GLenum type, GLsizei count, const GLchar *const* strings);
typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKKHRPROC)(GLDEBUGPROCKHR callback, const void * userParam);
typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLKHRPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled);
typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTKHRPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf);

View File

@ -139,13 +139,21 @@ information on what to include when reporting a bug.
- Added `GLFW_POINTING_HAND_CURSOR` alias for `GLFW_HAND_CURSOR` (#427)
- Added `GLFW_MOUSE_PASSTHROUGH` window hint for letting mouse input pass
through the window (#1236,#1568)
- Added `GLFW_CURSOR_CAPTURED` cursor mode to confine the cursor to the window
content area (#58)
- Added `GLFW_POSITION_X` and `GLFW_POSITION_Y` window hints for initial position
(#1603,#1747)
- Added `GLFW_ANY_POSITION` hint value for letting the window manager choose (#1603,#1747)
- Added `GLFW_PLATFORM_UNAVAILABLE` error for platform detection failures (#1958)
- Added `GLFW_FEATURE_UNAVAILABLE` error for platform limitations (#1692)
- Added `GLFW_FEATURE_UNIMPLEMENTED` error for incomplete backends (#1692)
- Added `GLFW_WAYLAND_APP_ID` window hint string for Wayland app\_id selection
(#2121,#2122)
- Added `GLFW_ANGLE_PLATFORM_TYPE` init hint and `GLFW_ANGLE_PLATFORM_TYPE_*`
values to select ANGLE backend (#1380)
- Added `GLFW_X11_XCB_VULKAN_SURFACE` init hint for selecting X11 Vulkan
surface extension (#1793)
- Added `GLFW_NATIVE_INCLUDE_NONE` for disabling inclusion of native headers (#1348)
- Added `GLFW_BUILD_WIN32` CMake option for enabling Win32 support (#1958)
- Added `GLFW_BUILD_COCOA` CMake option for enabling Cocoa support (#1958)
- Added `GLFW_BUILD_X11` CMake option for enabling X11 support (#1958)
@ -172,9 +180,13 @@ information on what to include when reporting a bug.
- Bugfix: Gamepad mapping updates could spam `GLFW_INVALID_VALUE` due to
incompatible controllers sharing hardware ID (#1763)
- Bugfix: Native access functions for context handles did not check that the API matched
- Bugfix: `glfwMakeContextCurrent` would access TLS slot before initialization
- Bugfix: `glfwSetGammaRamp` could emit `GLFW_INVALID_VALUE` before initialization
- Bugfix: `glfwGetJoystickUserPointer` returned `NULL` during disconnection (#2092)
- [Win32] Added the `GLFW_WIN32_KEYBOARD_MENU` window hint for enabling access
to the window menu
- [Win32] Added a version info resource to the GLFW DLL
- [Win32] Made hidden helper window use its own window class
- [Win32] Disabled framebuffer transparency on Windows 7 when DWM windows are
opaque (#1512)
- [Win32] Bugfix: `GLFW_INCLUDE_VULKAN` plus `VK_USE_PLATFORM_WIN32_KHR` caused
@ -205,12 +217,25 @@ information on what to include when reporting a bug.
- [Win32] Bugfix: Content scale queries could fail silently (#1615)
- [Win32] Bugfix: Content scales could have garbage values if monitor was recently
disconnected (#1615)
- [Win32] Bugfix: A window created maximized and undecorated would cover the whole
monitor (#1806)
- [Win32] Bugfix: The default restored window position was lost when creating a maximized
window
- [Win32] Bugfix: `glfwMaximizeWindow` would make a hidden window visible
- [Win32] Bugfix: `Alt+PrtSc` would emit `GLFW_KEY_UNKNOWN` and a different
scancode than `PrtSc` (#1993)
- [Win32] Bugfix: `GLFW_KEY_PAUSE` scancode from `glfwGetKeyScancode` did not
match event scancode (#1993)
- [Win32] Bugfix: Instance-local operations used executable instance (#469,#1296,#1395)
- [Win32] Bugfix: The OSMesa library was not unloaded on termination
- [Win32] Bugfix: Right shift emitted `GLFW_KEY_UNKNOWN` when using a CJK IME (#2050)
- [Cocoa] Added support for `VK_EXT_metal_surface` (#1619)
- [Cocoa] Added locating the Vulkan loader at runtime in an application bundle
- [Cocoa] Moved main menu creation to GLFW initialization time (#1649)
- [Cocoa] Changed `EGLNativeWindowType` from `NSView` to `CALayer` (#1169)
- [Cocoa] Changed F13 key to report Print Screen for cross-platform consistency
(#1786)
- [Cocoa] Disabled macOS fullscreen when `GLFW_RESIZABLE` is false
- [Cocoa] Removed dependency on the CoreVideo framework
- [Cocoa] Bugfix: `glfwSetWindowSize` used a bottom-left anchor point (#1553)
- [Cocoa] Bugfix: Window remained on screen after destruction until event poll
@ -234,6 +259,16 @@ information on what to include when reporting a bug.
- [Cocoa] Bugfix: Moving the cursor programmatically would freeze it for
a fraction of a second (#1962)
- [Cocoa] Bugfix: `kIOMasterPortDefault` was deprecated in macOS 12.0 (#1980)
- [Cocoa] Bugfix: `kUTTypeURL` was deprecated in macOS 12.0 (#2003)
- [Cocoa] Bugfix: A connected Apple AirPlay would emit a useless error (#1791)
- [Cocoa] Bugfix: The EGL and OSMesa libraries were not unloaded on termination
- [Cocoa] Bugfix: `GLFW_MAXIMIZED` was always true when `GLFW_RESIZABLE` was false
- [Cocoa] Bugfix: Changing `GLFW_DECORATED` in macOS fullscreen would abort
application (#1886)
- [Cocoa] Bugfix: Setting a monitor from macOS fullscreen would abort
application (#2110)
- [Cocoa] Bugfix: The Vulkan loader was not loaded from the `Frameworks` bundle
subdirectory (#2113,#2120)
- [X11] Bugfix: The CMake files did not check for the XInput headers (#1480)
- [X11] Bugfix: Key names were not updated when the keyboard layout changed
(#1462,#1528)
@ -265,8 +300,23 @@ information on what to include when reporting a bug.
- [X11] Bugfix: Icon pixel format conversion worked only by accident, relying on
undefined behavior (#1986)
- [X11] Bugfix: Dynamic loading on OpenBSD failed due to soname differences
- [X11] Bugfix: Waiting for events would fail if file descriptor was too large
(#2024)
- [X11] Bugfix: Joystick events could lead to busy-waiting (#1872)
- [X11] Bugfix: `glfwWaitEvents*` did not continue for joystick events
- [X11] Bugfix: `glfwPostEmptyEvent` could be ignored due to race condition
(#379,#1281,#1285,#2033)
- [X11] Bugfix: Dynamic loading on NetBSD failed due to soname differences
- [X11] Bugfix: Left shift of int constant relied on undefined behavior (#1951)
- [X11] Bugfix: The OSMesa libray was not unloaded on termination
- [X11] Bugfix: A malformed response during selection transfer could cause a segfault
- [X11] Bugfix: Some calls would reset Xlib to the default error handler (#2108)
- [Wayland] Added dynamic loading of all Wayland libraries
- [Wayland] Added support for key names via xkbcommon
- [Wayland] Added support for file path drop events (#2040)
- [Wayland] Added support for more human-readable monitor names where available
- [Wayland] Disabled alpha channel for opaque windows on systems lacking
`EGL_EXT_present_opaque` (#1895)
- [Wayland] Removed support for `wl_shell` (#1443)
- [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432)
- [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled
@ -289,8 +339,52 @@ information on what to include when reporting a bug.
- [Wayland] Bugfix: Full screen window creation did not ignore `GLFW_VISIBLE`
- [Wayland] Bugfix: Some keys were reported as wrong key or `GLFW_KEY_UNKNOWN`
- [Wayland] Bugfix: Text input did not repeat along with key repeat
- [Wayland] Bugfix: `glfwPostEmptyEvent` sometimes had no effect (#1520,#1521)
- [Wayland] Bugfix: `glfwSetClipboardString` would fail if set to result of
`glfwGetClipboardString`
- [Wayland] Bugfix: Data source creation error would cause double free at termination
- [Wayland] Bugfix: Partial writes of clipboard string would cause beginning to repeat
- [Wayland] Bugfix: Some errors would cause clipboard string transfer to hang
- [Wayland] Bugfix: Drag and drop data was misinterpreted as clipboard string
- [Wayland] Bugfix: MIME type matching was not performed for clipboard string
- [Wayland] Bugfix: The OSMesa library was not unloaded on termination
- [Wayland] Bugfix: `glfwCreateWindow` could emit `GLFW_FEATURE_UNAVAILABLE`
- [Wayland] Bugfix: Lock key modifier bits were only set when lock keys were pressed
- [Wayland] Bugfix: A window leaving full screen mode would be iconified (#1995)
- [Wayland] Bugfix: A window leaving full screen mode ignored its desired size
- [Wayland] Bugfix: `glfwSetWindowMonitor` did not update windowed mode size
- [Wayland] Bugfix: `glfwRestoreWindow` would make a full screen window windowed
- [Wayland] Bugfix: A window maximized or restored by the user would enter an
inconsistent state
- [Wayland] Bugfix: Window maximization events were not emitted
- [Wayland] Bugfix: `glfwRestoreWindow` assumed it was always in windowed mode
- [Wayland] Bugfix: `glfwSetWindowSize` would resize a full screen window
- [Wayland] Bugfix: A window content scale event would be emitted every time
the window resized
- [Wayland] Bugfix: If `glfwInit` failed it would close stdin
- [Wayland] Bugfix: Manual resizing with fallback decorations behaved erratically
(#1991,#2115,#2127)
- [Wayland] Bugfix: Size limits included frame size for fallback decorations
- [Wayland] Bugfix: Updating `GLFW_DECORATED` had no effect on server-side
decorations
- [Wayland] Bugfix: A monitor would be reported as connected again if its scale
changed
- [Wayland] Bugfix: `glfwTerminate` would segfault if any monitor had changed
scale
- [Wayland] Bugfix: Window content scale events were not emitted when monitor
scale changed
- [Wayland] Bugfix: `glfwSetWindowAspectRatio` reported an error instead of
applying the specified ratio
- [Wayland] Bugfix: `GLFW_MAXIMIZED` window hint had no effect
- [Wayland] Bugfix: `glfwRestoreWindow` had no effect before first show
- [Wayland] Bugfix: Hiding and then showing a window caused program abort on
wlroots compositors (#1268)
- [Wayland] Bugfix: `GLFW_DECORATED` was ignored when showing a window with XDG
decorations
- [Wayland] Bugfix: Connecting a mouse after `glfwInit` would segfault (#1450)
- [POSIX] Removed use of deprecated function `gettimeofday`
- [POSIX] Bugfix: `CLOCK_MONOTONIC` was not correctly tested for or enabled
- [Linux] Bugfix: Joysticks without buttons were ignored (#2042,#2043)
- [WGL] Disabled the DWM swap interval hack for Windows 8 and later (#1072)
- [NSGL] Removed enforcement of forward-compatible flag for core contexts
- [NSGL] Bugfix: `GLFW_COCOA_RETINA_FRAMEBUFFER` had no effect on newer
@ -302,7 +396,10 @@ information on what to include when reporting a bug.
(#442)
- [EGL] Added ANGLE backend selection via `EGL_ANGLE_platform_angle` extension
(#1380)
[EGL] Added loading of glvnd `libOpenGL.so.0` where available for OpenGL
- [EGL] Bugfix: The `GLFW_DOUBLEBUFFER` context attribute was ignored (#1843)
- [GLX] Added loading of glvnd `libGLX.so.0` where available
- [GLX] Bugfix: Context creation failed if GLX 1.4 was not exported by GLX library
## Contact

View File

@ -262,13 +262,12 @@ extern "C" {
/* We are building GLFW as a Win32 DLL */
#define GLFWAPI __declspec(dllexport)
#elif defined(_WIN32) && defined(GLFW_DLL)
/* We are calling GLFW as a Win32 DLL */
/* We are calling a GLFW Win32 DLL */
#define GLFWAPI __declspec(dllimport)
#elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL)
/* We are building GLFW as a shared / dynamic library */
/* We are building GLFW as a Unix shared library */
#define GLFWAPI __attribute__((visibility("default")))
#else
/* We are building or calling GLFW as a static library */
#define GLFWAPI
#endif
@ -928,6 +927,18 @@ extern "C" {
*/
#define GLFW_MOUSE_PASSTHROUGH 0x0002000D
/*! @brief Initial position x-coordinate window hint.
*
* Initial position x-coordinate [window hint](@ref GLFW_POSITION_X).
*/
#define GLFW_POSITION_X 0x0002000E
/*! @brief Initial position y-coordinate window hint.
*
* Initial position y-coordinate [window hint](@ref GLFW_POSITION_Y).
*/
#define GLFW_POSITION_Y 0x0002000F
/*! @brief Framebuffer bit depth hint.
*
* Framebuffer bit depth [hint](@ref GLFW_RED_BITS).
@ -1106,6 +1117,12 @@ extern "C" {
*/
#define GLFW_X11_INSTANCE_NAME 0x00024002
#define GLFW_WIN32_KEYBOARD_MENU 0x00025001
/*! @brief Wayland specific
* [window hint](@ref GLFW_WAYLAND_APP_ID_hint).
*
* Allows specification of the Wayland app_id.
*/
#define GLFW_WAYLAND_APP_ID 0x00026001
/*! @} */
#define GLFW_NO_API 0
@ -1129,6 +1146,7 @@ extern "C" {
#define GLFW_CURSOR_NORMAL 0x00034001
#define GLFW_CURSOR_HIDDEN 0x00034002
#define GLFW_CURSOR_DISABLED 0x00034003
#define GLFW_CURSOR_CAPTURED 0x00034004
#define GLFW_ANY_RELEASE_BEHAVIOR 0
#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001
@ -1146,6 +1164,8 @@ extern "C" {
#define GLFW_ANGLE_PLATFORM_TYPE_VULKAN 0x00037007
#define GLFW_ANGLE_PLATFORM_TYPE_METAL 0x00037008
#define GLFW_ANY_POSITION 0x80000000
/*! @defgroup shapes Standard cursor shapes
* @brief Standard system cursor shapes.
*
@ -2815,11 +2835,11 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor);
* @param[in] monitor The monitor whose gamma ramp to set.
* @param[in] gamma The desired exponent.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_INVALID_VALUE,
* @ref GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
*
* @remark @wayland Gamma handling is a privileged protocol, this function
* will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR.
* will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
*
* @thread_safety This function must only be called from the main thread.
*
@ -2839,11 +2859,11 @@ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma);
* @return The current gamma ramp, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_PLATFORM_ERROR
* and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
*
* @remark @wayland Gamma handling is a privileged protocol, this function
* will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR while
* will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE while
* returning `NULL`.
*
* @pointer_lifetime The returned structure and its arrays are allocated and
@ -2878,8 +2898,8 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
* @param[in] monitor The monitor whose gamma ramp to set.
* @param[in] ramp The gamma ramp to use.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref GLFW_PLATFORM_ERROR
* and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
*
* @remark The size of the specified gamma ramp should match the size of the
* current ramp for that monitor.
@ -2887,7 +2907,7 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor);
* @remark @win32 The gamma ramp size must be 256.
*
* @remark @wayland Gamma handling is a privileged protocol, this function
* will thus never be implemented and emits @ref GLFW_PLATFORM_ERROR.
* will thus never be implemented and emits @ref GLFW_FEATURE_UNAVAILABLE.
*
* @pointer_lifetime The specified gamma ramp is copied before this function
* returns.
@ -3030,10 +3050,10 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value);
* OpenGL or OpenGL ES context.
*
* By default, newly created windows use the placement recommended by the
* window system. To create the window at a specific position, make it
* initially invisible using the [GLFW_VISIBLE](@ref GLFW_VISIBLE_hint) window
* hint, set its [position](@ref window_pos) and then [show](@ref window_hide)
* it.
* window system. To create the window at a specific position, set the @ref
* GLFW_POSITION_X and @ref GLFW_POSITION_Y window hints before creation. To
* restore the default behavior, set either or both hints back to
* `GLFW_ANY_POSITION`.
*
* As long as at least one full screen window is not iconified, the screensaver
* is prohibited from starting.
@ -3258,7 +3278,8 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title);
* count is zero.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
* GLFW_INVALID_VALUE, @ref GLFW_PLATFORM_ERROR and @ref
* GLFW_FEATURE_UNAVAILABLE (see remarks).
*
* @pointer_lifetime The specified image data is copied before this function
* returns.
@ -3671,8 +3692,9 @@ GLFWAPI void glfwSetWindowOpacity(GLFWwindow* window, float opacity);
* previously restored. If the window is already iconified, this function does
* nothing.
*
* If the specified window is a full screen window, the original monitor
* resolution is restored until the window is restored.
* If the specified window is a full screen window, GLFW restores the original
* video mode of the monitor. The window's desired video mode is set again
* when the window is restored.
*
* @param[in] window The window to iconify.
*
@ -3702,8 +3724,8 @@ GLFWAPI void glfwIconifyWindow(GLFWwindow* window);
* (minimized) or maximized. If the window is already restored, this function
* does nothing.
*
* If the specified window is a full screen window, the resolution chosen for
* the window is restored on the selected monitor.
* If the specified window is an iconified full screen window, its desired
* video mode is set again for its monitor when the window is restored.
*
* @param[in] window The window to restore.
*
@ -3971,6 +3993,9 @@ GLFWAPI void glfwSetWindowMonitor(GLFWwindow* window, GLFWmonitor* monitor, int
* errors. However, this function should not fail as long as it is passed
* valid arguments and the library has been [initialized](@ref intro_init).
*
* @remark @wayland The Wayland protocol provides no way to check whether a
* window is iconfied, so @ref GLFW_ICONIFIED always returns `GLFW_FALSE`.
*
* @thread_safety This function must only be called from the main thread.
*
* @sa @ref window_attribs
@ -4005,7 +4030,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib);
* @param[in] value `GLFW_TRUE` or `GLFW_FALSE`.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
* GLFW_INVALID_ENUM, @ref GLFW_INVALID_VALUE, @ref GLFW_PLATFORM_ERROR and @ref
* GLFW_FEATURE_UNAVAILABLE.
*
* @remark Calling @ref glfwGetWindowAttrib will always return the latest
* value, even if that value is ignored by the current mode of the window.
@ -4556,6 +4582,8 @@ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode);
* - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual
* and unlimited cursor movement. This is useful for implementing for
* example 3D camera controls.
* - `GLFW_CURSOR_CAPTURED` makes the cursor visible and confines it to the
* content area of the window.
*
* If the mode is `GLFW_STICKY_KEYS`, the value must be either `GLFW_TRUE` to
* enable sticky keys, or `GLFW_FALSE` to disable it. If sticky keys are
@ -4730,8 +4758,7 @@ GLFWAPI int glfwGetKeyScancode(int key);
*
* This function returns the last state reported for the specified key to the
* specified window. The returned state is one of `GLFW_PRESS` or
* `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to
* the key callback.
* `GLFW_RELEASE`. The action `GLFW_REPEAT` is only reported to the key callback.
*
* If the @ref GLFW_STICKY_KEYS input mode is enabled, this function returns
* `GLFW_PRESS` the first time you call it for a key that was pressed, even if
@ -4855,11 +4882,11 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos);
* @param[in] ypos The desired y-coordinate, relative to the top edge of the
* content area.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_PLATFORM_ERROR and @ref GLFW_FEATURE_UNAVAILABLE (see remarks).
*
* @remark @wayland This function will only work when the cursor mode is
* `GLFW_CURSOR_DISABLED`, otherwise it will do nothing.
* `GLFW_CURSOR_DISABLED`, otherwise it will emit @ref GLFW_FEATURE_UNAVAILABLE.
*
* @thread_safety This function must only be called from the main thread.
*
@ -4892,8 +4919,8 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos);
* @return The handle of the created cursor, or `NULL` if an
* [error](@ref error_handling) occurred.
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED and @ref
* GLFW_PLATFORM_ERROR.
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED, @ref
* GLFW_INVALID_VALUE and @ref GLFW_PLATFORM_ERROR.
*
* @pointer_lifetime The specified image data is copied before this function
* returns.
@ -6383,6 +6410,7 @@ GLFWAPI VkResult glfwCreateWindowSurface(VkInstance instance, GLFWwindow* window
*/
#ifndef GLAPIENTRY
#define GLAPIENTRY APIENTRY
#define GLFW_GLAPIENTRY_DEFINED
#endif
/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */

View File

@ -74,6 +74,16 @@ extern "C" {
* and which platform-specific headers to include. It is then up your (by
* definition platform-specific) code to handle which of these should be
* defined.
*
* If you do not want the platform-specific headers to be included, define
* `GLFW_NATIVE_INCLUDE_NONE` before including the @ref glfw3native.h header.
*
* @code
* #define GLFW_EXPOSE_NATIVE_WIN32
* #define GLFW_EXPOSE_NATIVE_WGL
* #define GLFW_NATIVE_INCLUDE_NONE
* #include <GLFW/glfw3native.h>
* @endcode
*/
@ -81,44 +91,71 @@ extern "C" {
* System headers and types
*************************************************************************/
#if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL)
// This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
// example to allow applications to correctly declare a GL_KHR_debug callback)
// but windows.h assumes no one will define APIENTRY before it does
#if defined(GLFW_APIENTRY_DEFINED)
#undef APIENTRY
#undef GLFW_APIENTRY_DEFINED
#endif
#include <windows.h>
#elif defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL)
#if defined(__OBJC__)
#import <Cocoa/Cocoa.h>
#else
//#include <ApplicationServices/ApplicationServices.h>
typedef void* id;
#endif
#elif defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#elif defined(GLFW_EXPOSE_NATIVE_WAYLAND)
#include <wayland-client.h>
#endif
#if !defined(GLFW_NATIVE_INCLUDE_NONE)
#if defined(GLFW_EXPOSE_NATIVE_WGL)
/* WGL is declared by windows.h */
#endif
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
/* NSGL is declared by Cocoa.h */
#endif
#if defined(GLFW_EXPOSE_NATIVE_GLX)
#include <GL/glx.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_EGL)
#include <EGL/egl.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
#include <GL/osmesa.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_WIN32) || defined(GLFW_EXPOSE_NATIVE_WGL)
/* This is a workaround for the fact that glfw3.h needs to export APIENTRY (for
* example to allow applications to correctly declare a GL_KHR_debug callback)
* but windows.h assumes no one will define APIENTRY before it does
*/
#if defined(GLFW_APIENTRY_DEFINED)
#undef APIENTRY
#undef GLFW_APIENTRY_DEFINED
#endif
#include <windows.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_COCOA) || defined(GLFW_EXPOSE_NATIVE_NSGL)
#if defined(__OBJC__)
#import <Cocoa/Cocoa.h>
#else
#include <ApplicationServices/ApplicationServices.h>
#include <objc/objc.h>
#endif
#endif
#if defined(GLFW_EXPOSE_NATIVE_X11) || defined(GLFW_EXPOSE_NATIVE_GLX)
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_WAYLAND)
#include <wayland-client.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_WGL)
/* WGL is declared by windows.h */
#endif
#if defined(GLFW_EXPOSE_NATIVE_NSGL)
/* NSGL is declared by Cocoa.h */
#endif
#if defined(GLFW_EXPOSE_NATIVE_GLX)
/* This is a workaround for the fact that glfw3.h defines GLAPIENTRY because by
* default it also acts as an OpenGL header
* However, glx.h will include gl.h, which will define it unconditionally
*/
#if defined(GLFW_GLAPIENTRY_DEFINED)
#undef GLAPIENTRY
#undef GLFW_GLAPIENTRY_DEFINED
#endif
#include <GL/glx.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_EGL)
#include <EGL/egl.h>
#endif
#if defined(GLFW_EXPOSE_NATIVE_OSMESA)
/* This is a workaround for the fact that glfw3.h defines GLAPIENTRY because by
* default it also acts as an OpenGL header
* However, osmesa.h will include gl.h, which will define it unconditionally
*/
#if defined(GLFW_GLAPIENTRY_DEFINED)
#undef GLAPIENTRY
#undef GLFW_GLAPIENTRY_DEFINED
#endif
#include <GL/osmesa.h>
#endif
#endif /*GLFW_NATIVE_INCLUDE_NONE*/
/*************************************************************************
@ -227,7 +264,7 @@ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window);
*
* @ingroup native
*/
GLFWAPI uint32_t glfwGetCocoaMonitor(GLFWmonitor* monitor);
GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor);
/*! @brief Returns the `NSWindow` of the specified window.
*
@ -475,6 +512,9 @@ GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window);
*
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
*
* @remark Because EGL is initialized on demand, this function will return
* `EGL_NO_DISPLAY` until the first context has been created via EGL.
*
* @thread_safety This function may be called from any thread. Access is not
* synchronized.
*

View File

@ -60,6 +60,7 @@ if (GLFW_BUILD_X11 OR GLFW_BUILD_WAYLAND)
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_sources(glfw PRIVATE linux_joystick.h linux_joystick.c)
endif()
target_sources(glfw PRIVATE posix_poll.h posix_poll.c)
endif()
if (GLFW_BUILD_WAYLAND)

View File

@ -27,6 +27,9 @@
//========================================================================
#include "internal.h"
#if defined(_GLFW_COCOA)
#include <sys/param.h> // For MAXPATHLEN
// Needed for _NSGetProgname
@ -460,18 +463,26 @@ void* _glfwLoadLocalVulkanLoaderCocoa(void)
if (!bundle)
return NULL;
CFURLRef url =
CFBundleCopyAuxiliaryExecutableURL(bundle, CFSTR("libvulkan.1.dylib"));
if (!url)
CFURLRef frameworksUrl = CFBundleCopyPrivateFrameworksURL(bundle);
if (!frameworksUrl)
return NULL;
CFURLRef loaderUrl = CFURLCreateCopyAppendingPathComponent(
kCFAllocatorDefault, frameworksUrl, CFSTR("libvulkan.1.dylib"), false);
if (!loaderUrl)
{
CFRelease(frameworksUrl);
return NULL;
}
char path[PATH_MAX];
void* handle = NULL;
if (CFURLGetFileSystemRepresentation(url, true, (UInt8*) path, sizeof(path) - 1))
if (CFURLGetFileSystemRepresentation(loaderUrl, true, (UInt8*) path, sizeof(path) - 1))
handle = _glfwPlatformLoadModule(path);
CFRelease(url);
CFRelease(loaderUrl);
CFRelease(frameworksUrl);
return handle;
}
@ -676,7 +687,11 @@ void _glfwTerminateCocoa(void)
_glfw_free(_glfw.ns.clipboardString);
_glfwTerminateNSGL();
_glfwTerminateEGL();
_glfwTerminateOSMesa();
} // autoreleasepool
}
#endif // _GLFW_COCOA

View File

@ -31,8 +31,6 @@
#define GLFW_COCOA_JOYSTICK_STATE _GLFWjoystickNS ns;
#define GLFW_COCOA_LIBRARY_JOYSTICK_STATE
#define GLFW_BUILD_COCOA_MAPPINGS
// Cocoa-specific per-joystick data
//
typedef struct _GLFWjoystickNS
@ -45,7 +43,7 @@ typedef struct _GLFWjoystickNS
GLFWbool _glfwInitJoysticksCocoa(void);
void _glfwTerminateJoysticksCocoa(void);
int _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode);
GLFWbool _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode);
const char* _glfwGetMappingNameCocoa(void);
void _glfwUpdateGamepadGUIDCocoa(char* guid);

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(_GLFW_COCOA)
#include <unistd.h>
#include <ctype.h>
#include <string.h>
@ -96,8 +98,7 @@ static CFComparisonResult compareElements(const void* fp,
//
static void closeJoystick(_GLFWjoystick* js)
{
if (!js->present)
return;
_glfwInputJoystick(js, GLFW_DISCONNECTED);
for (int i = 0; i < CFArrayGetCount(js->ns.axes); i++)
_glfw_free((void*) CFArrayGetValueAtIndex(js->ns.axes, i));
@ -112,7 +113,6 @@ static void closeJoystick(_GLFWjoystick* js)
CFRelease(js->ns.hats);
_glfwFreeJoystick(js);
_glfwInputJoystick(js, GLFW_DISCONNECTED);
}
// Callback for user-initiated joystick addition
@ -289,9 +289,9 @@ static void removeCallback(void* context,
{
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (_glfw.joysticks[jid].ns.device == device)
if (_glfw.joysticks[jid].connected && _glfw.joysticks[jid].ns.device == device)
{
closeJoystick(_glfw.joysticks + jid);
closeJoystick(&_glfw.joysticks[jid]);
break;
}
}
@ -382,7 +382,10 @@ GLFWbool _glfwInitJoysticksCocoa(void)
void _glfwTerminateJoysticksCocoa(void)
{
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
closeJoystick(_glfw.joysticks + jid);
{
if (_glfw.joysticks[jid].connected)
closeJoystick(&_glfw.joysticks[jid]);
}
if (_glfw.ns.hidManager)
{
@ -392,7 +395,7 @@ void _glfwTerminateJoysticksCocoa(void)
}
int _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode)
GLFWbool _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode)
{
if (mode & _GLFW_POLL_AXES)
{
@ -455,7 +458,7 @@ int _glfwPollJoystickCocoa(_GLFWjoystick* js, int mode)
}
}
return js->present;
return js->connected;
}
const char* _glfwGetMappingNameCocoa(void)
@ -475,3 +478,5 @@ void _glfwUpdateGamepadGUIDCocoa(char* guid)
}
}
#endif // _GLFW_COCOA

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(_GLFW_COCOA)
#include <stdlib.h>
#include <limits.h>
#include <math.h>
@ -98,11 +100,7 @@ static char* getMonitorName(CGDirectDisplayID displayID, NSScreen* screen)
IOObjectRelease(it);
if (!service)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Cocoa: Failed to find service port for display");
return _glfw_strdup("Display");
}
CFDictionaryRef names =
CFDictionaryGetValue(info, CFSTR(kDisplayProductName));
@ -629,3 +627,5 @@ GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* handle)
return monitor->ns.displayID;
}
#endif // _GLFW_COCOA

View File

@ -42,16 +42,15 @@ typedef void* id;
#endif
// NOTE: Many Cocoa enum values have been renamed and we need to build across
// SDK versions where one is unavailable or the other deprecated
// We use the newer names in code and these macros to handle compatibility
// SDK versions where one is unavailable or deprecated.
// We use the newer names in code and replace them with the older names if
// the base SDK does not provide the newer names.
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101400
#define NSOpenGLContextParameterSwapInterval NSOpenGLCPSwapInterval
#define NSOpenGLContextParameterSurfaceOpacity NSOpenGLCPSurfaceOpacity
#endif
// NOTE: Many Cocoa enum values have been renamed and we need to build across
// SDK versions where one is unavailable or the other deprecated
// We use the newer names in code and these macros to handle compatibility
#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200
#define NSBitmapFormatAlphaNonpremultiplied NSAlphaNonpremultipliedBitmapFormat
#define NSEventMaskAny NSAnyEventMask
@ -70,6 +69,15 @@ typedef void* id;
#define NSWindowStyleMaskTitled NSTitledWindowMask
#endif
// NOTE: Many Cocoa dynamically linked constants have been renamed and we need
// to build across SDK versions where one is unavailable or deprecated.
// We use the newer names in code and replace them with the older names if
// the deployment target is older than the newer names.
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101300
#define NSPasteboardTypeURL NSURLPboardType
#endif
typedef VkFlags VkMacOSSurfaceCreateFlagsMVK;
typedef VkFlags VkMetalSurfaceCreateFlagsEXT;
@ -206,7 +214,7 @@ GLFWbool _glfwConnectCocoa(int platformID, _GLFWplatform* platform);
int _glfwInitCocoa(void);
void _glfwTerminateCocoa(void);
int _glfwCreateWindowCocoa(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
GLFWbool _glfwCreateWindowCocoa(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
void _glfwDestroyWindowCocoa(_GLFWwindow* window);
void _glfwSetWindowTitleCocoa(_GLFWwindow* window, const char* title);
void _glfwSetWindowIconCocoa(_GLFWwindow* window, int count, const GLFWimage* images);
@ -227,12 +235,12 @@ void _glfwHideWindowCocoa(_GLFWwindow* window);
void _glfwRequestWindowAttentionCocoa(_GLFWwindow* window);
void _glfwFocusWindowCocoa(_GLFWwindow* window);
void _glfwSetWindowMonitorCocoa(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate);
int _glfwWindowFocusedCocoa(_GLFWwindow* window);
int _glfwWindowIconifiedCocoa(_GLFWwindow* window);
int _glfwWindowVisibleCocoa(_GLFWwindow* window);
int _glfwWindowMaximizedCocoa(_GLFWwindow* window);
int _glfwWindowHoveredCocoa(_GLFWwindow* window);
int _glfwFramebufferTransparentCocoa(_GLFWwindow* window);
GLFWbool _glfwWindowFocusedCocoa(_GLFWwindow* window);
GLFWbool _glfwWindowIconifiedCocoa(_GLFWwindow* window);
GLFWbool _glfwWindowVisibleCocoa(_GLFWwindow* window);
GLFWbool _glfwWindowMaximizedCocoa(_GLFWwindow* window);
GLFWbool _glfwWindowHoveredCocoa(_GLFWwindow* window);
GLFWbool _glfwFramebufferTransparentCocoa(_GLFWwindow* window);
void _glfwSetWindowResizableCocoa(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowDecoratedCocoa(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowFloatingCocoa(_GLFWwindow* window, GLFWbool enabled);
@ -253,8 +261,8 @@ void _glfwSetCursorPosCocoa(_GLFWwindow* window, double xpos, double ypos);
void _glfwSetCursorModeCocoa(_GLFWwindow* window, int mode);
const char* _glfwGetScancodeNameCocoa(int scancode);
int _glfwGetKeyScancodeCocoa(int key);
int _glfwCreateCursorCocoa(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
int _glfwCreateStandardCursorCocoa(_GLFWcursor* cursor, int shape);
GLFWbool _glfwCreateCursorCocoa(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
GLFWbool _glfwCreateStandardCursorCocoa(_GLFWcursor* cursor, int shape);
void _glfwDestroyCursorCocoa(_GLFWcursor* cursor);
void _glfwSetCursorCocoa(_GLFWwindow* window, _GLFWcursor* cursor);
void _glfwSetClipboardStringCocoa(const char* string);
@ -265,7 +273,7 @@ EGLNativeDisplayType _glfwGetEGLNativeDisplayCocoa(void);
EGLNativeWindowType _glfwGetEGLNativeWindowCocoa(_GLFWwindow* window);
void _glfwGetRequiredInstanceExtensionsCocoa(char** extensions);
int _glfwGetPhysicalDevicePresentationSupportCocoa(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
GLFWbool _glfwGetPhysicalDevicePresentationSupportCocoa(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceCocoa(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
void _glfwFreeMonitorCocoa(_GLFWmonitor* monitor);

View File

@ -28,6 +28,8 @@
#include "internal.h"
#if defined(GLFW_BUILD_COCOA_TIMER)
#include <mach/mach_time.h>
@ -53,3 +55,5 @@ uint64_t _glfwPlatformGetTimerFrequency(void)
return _glfw.timer.ns.frequency;
}
#endif // GLFW_BUILD_COCOA_TIMER

View File

@ -28,28 +28,14 @@
#include "internal.h"
#if defined(_GLFW_COCOA)
#include <float.h>
#include <string.h>
// Returns the style mask corresponding to the window settings
//
static NSUInteger getStyleMask(_GLFWwindow* window)
{
NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
if (window->monitor || !window->decorated)
styleMask |= NSWindowStyleMaskBorderless;
else
{
styleMask |= NSWindowStyleMaskTitled |
NSWindowStyleMaskClosable;
if (window->resizable)
styleMask |= NSWindowStyleMaskResizable;
}
return styleMask;
}
// HACK: This enum value is missing from framework headers on OS X 10.11 despite
// having been (according to documentation) added in Mac OS X 10.7
#define NSWindowCollectionBehaviorFullScreenNone (1 << 9)
// Returns whether the cursor is in the content area of the specified window
//
@ -361,9 +347,7 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
markedText = [[NSMutableAttributedString alloc] init];
[self updateTrackingAreas];
// NOTE: kUTTypeURL corresponds to NSPasteboardTypeURL but is available
// on 10.7 without having been deprecated yet
[self registerForDraggedTypes:@[(__bridge NSString*) kUTTypeURL]];
[self registerForDraggedTypes:@[NSPasteboardTypeURL]];
}
return self;
@ -809,11 +793,35 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
contentRect = NSMakeRect(xpos, ypos, mode.width, mode.height);
}
else
contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height);
{
if (wndconfig->xpos == GLFW_ANY_POSITION ||
wndconfig->ypos == GLFW_ANY_POSITION)
{
contentRect = NSMakeRect(0, 0, wndconfig->width, wndconfig->height);
}
else
{
const int xpos = wndconfig->xpos;
const int ypos = _glfwTransformYCocoa(wndconfig->ypos + wndconfig->height - 1);
contentRect = NSMakeRect(xpos, ypos, wndconfig->width, wndconfig->height);
}
}
NSUInteger styleMask = NSWindowStyleMaskMiniaturizable;
if (window->monitor || !window->decorated)
styleMask |= NSWindowStyleMaskBorderless;
else
{
styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
if (window->resizable)
styleMask |= NSWindowStyleMaskResizable;
}
window->ns.object = [[GLFWWindow alloc]
initWithContentRect:contentRect
styleMask:getStyleMask(window)
styleMask:styleMask
backing:NSBackingStoreBuffered
defer:NO];
@ -827,10 +835,14 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
[window->ns.object setLevel:NSMainMenuWindowLevel + 1];
else
{
[(NSWindow*) window->ns.object center];
_glfw.ns.cascadePoint =
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
if (wndconfig->xpos == GLFW_ANY_POSITION ||
wndconfig->ypos == GLFW_ANY_POSITION)
{
[(NSWindow*) window->ns.object center];
_glfw.ns.cascadePoint =
NSPointToCGPoint([window->ns.object cascadeTopLeftFromPoint:
NSPointFromCGPoint(_glfw.ns.cascadePoint)]);
}
if (wndconfig->resizable)
{
@ -839,6 +851,12 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
NSWindowCollectionBehaviorManaged;
[window->ns.object setCollectionBehavior:behavior];
}
else
{
const NSWindowCollectionBehavior behavior =
NSWindowCollectionBehaviorFullScreenNone;
[window->ns.object setCollectionBehavior:behavior];
}
if (wndconfig->floating)
[window->ns.object setLevel:NSFloatingWindowLevel];
@ -895,10 +913,10 @@ float _glfwTransformYCocoa(float y)
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwCreateWindowCocoa(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
GLFWbool _glfwCreateWindowCocoa(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
@autoreleasepool {
@ -933,13 +951,31 @@ int _glfwCreateWindowCocoa(_GLFWwindow* window,
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
}
if (wndconfig->mousePassthrough)
_glfwSetWindowMousePassthroughCocoa(window, GLFW_TRUE);
if (window->monitor)
{
_glfwShowWindowCocoa(window);
_glfwFocusWindowCocoa(window);
acquireMonitor(window);
if (wndconfig->centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig->visible)
{
_glfwShowWindowCocoa(window);
if (wndconfig->focused)
_glfwFocusWindowCocoa(window);
}
}
return GLFW_TRUE;
@ -1219,9 +1255,10 @@ void _glfwSetWindowMonitorCocoa(_GLFWwindow* window,
{
const NSRect contentRect =
NSMakeRect(xpos, _glfwTransformYCocoa(ypos + height - 1), width, height);
const NSUInteger styleMask = [window->ns.object styleMask];
const NSRect frameRect =
[window->ns.object frameRectForContentRect:contentRect
styleMask:getStyleMask(window)];
styleMask:styleMask];
[window->ns.object setFrame:frameRect display:YES];
}
@ -1238,7 +1275,27 @@ void _glfwSetWindowMonitorCocoa(_GLFWwindow* window,
// TODO: Solve this in a less terrible way
_glfwPollEventsCocoa();
const NSUInteger styleMask = getStyleMask(window);
NSUInteger styleMask = [window->ns.object styleMask];
if (window->monitor)
{
styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
styleMask |= NSWindowStyleMaskBorderless;
}
else
{
if (window->decorated)
{
styleMask &= ~NSWindowStyleMaskBorderless;
styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
}
if (window->resizable)
styleMask |= NSWindowStyleMaskResizable;
else
styleMask &= ~NSWindowStyleMaskResizable;
}
[window->ns.object setStyleMask:styleMask];
// HACK: Changing the style mask can cause the first responder to be cleared
[window->ns.object makeFirstResponder:window->ns.view];
@ -1284,6 +1341,20 @@ void _glfwSetWindowMonitorCocoa(_GLFWwindow* window,
else
[window->ns.object setLevel:NSNormalWindowLevel];
if (window->resizable)
{
const NSWindowCollectionBehavior behavior =
NSWindowCollectionBehaviorFullScreenPrimary |
NSWindowCollectionBehaviorManaged;
[window->ns.object setCollectionBehavior:behavior];
}
else
{
const NSWindowCollectionBehavior behavior =
NSWindowCollectionBehaviorFullScreenNone;
[window->ns.object setCollectionBehavior:behavior];
}
[window->ns.object setHasShadow:YES];
// HACK: Clearing NSWindowStyleMaskTitled resets and disables the window
// title property but the miniwindow title property is unaffected
@ -1293,35 +1364,40 @@ void _glfwSetWindowMonitorCocoa(_GLFWwindow* window,
} // autoreleasepool
}
int _glfwWindowFocusedCocoa(_GLFWwindow* window)
GLFWbool _glfwWindowFocusedCocoa(_GLFWwindow* window)
{
@autoreleasepool {
return [window->ns.object isKeyWindow];
} // autoreleasepool
}
int _glfwWindowIconifiedCocoa(_GLFWwindow* window)
GLFWbool _glfwWindowIconifiedCocoa(_GLFWwindow* window)
{
@autoreleasepool {
return [window->ns.object isMiniaturized];
} // autoreleasepool
}
int _glfwWindowVisibleCocoa(_GLFWwindow* window)
GLFWbool _glfwWindowVisibleCocoa(_GLFWwindow* window)
{
@autoreleasepool {
return [window->ns.object isVisible];
} // autoreleasepool
}
int _glfwWindowMaximizedCocoa(_GLFWwindow* window)
GLFWbool _glfwWindowMaximizedCocoa(_GLFWwindow* window)
{
@autoreleasepool {
return [window->ns.object isZoomed];
if (window->resizable)
return [window->ns.object isZoomed];
else
return GLFW_FALSE;
} // autoreleasepool
}
int _glfwWindowHoveredCocoa(_GLFWwindow* window)
GLFWbool _glfwWindowHoveredCocoa(_GLFWwindow* window)
{
@autoreleasepool {
@ -1339,7 +1415,7 @@ int _glfwWindowHoveredCocoa(_GLFWwindow* window)
} // autoreleasepool
}
int _glfwFramebufferTransparentCocoa(_GLFWwindow* window)
GLFWbool _glfwFramebufferTransparentCocoa(_GLFWwindow* window)
{
@autoreleasepool {
return ![window->ns.object isOpaque] && ![window->ns.view isOpaque];
@ -1349,15 +1425,46 @@ int _glfwFramebufferTransparentCocoa(_GLFWwindow* window)
void _glfwSetWindowResizableCocoa(_GLFWwindow* window, GLFWbool enabled)
{
@autoreleasepool {
[window->ns.object setStyleMask:getStyleMask(window)];
const NSUInteger styleMask = [window->ns.object styleMask];
if (enabled)
{
[window->ns.object setStyleMask:(styleMask | NSWindowStyleMaskResizable)];
const NSWindowCollectionBehavior behavior =
NSWindowCollectionBehaviorFullScreenPrimary |
NSWindowCollectionBehaviorManaged;
[window->ns.object setCollectionBehavior:behavior];
}
else
{
[window->ns.object setStyleMask:(styleMask & ~NSWindowStyleMaskResizable)];
const NSWindowCollectionBehavior behavior =
NSWindowCollectionBehaviorFullScreenNone;
[window->ns.object setCollectionBehavior:behavior];
}
} // autoreleasepool
}
void _glfwSetWindowDecoratedCocoa(_GLFWwindow* window, GLFWbool enabled)
{
@autoreleasepool {
[window->ns.object setStyleMask:getStyleMask(window)];
NSUInteger styleMask = [window->ns.object styleMask];
if (enabled)
{
styleMask |= (NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
styleMask &= ~NSWindowStyleMaskBorderless;
}
else
{
styleMask |= NSWindowStyleMaskBorderless;
styleMask &= ~(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable);
}
[window->ns.object setStyleMask:styleMask];
[window->ns.object makeFirstResponder:window->ns.view];
} // autoreleasepool
}
@ -1530,8 +1637,16 @@ void _glfwSetCursorPosCocoa(_GLFWwindow* window, double x, double y)
void _glfwSetCursorModeCocoa(_GLFWwindow* window, int mode)
{
@autoreleasepool {
if (mode == GLFW_CURSOR_CAPTURED)
{
_glfwInputError(GLFW_FEATURE_UNIMPLEMENTED,
"Cocoa: Captured cursor mode not yet implemented");
}
if (_glfwWindowFocusedCocoa(window))
updateCursorMode(window);
} // autoreleasepool
}
@ -1589,9 +1704,9 @@ int _glfwGetKeyScancodeCocoa(int key)
return _glfw.ns.scancodes[key];
}
int _glfwCreateCursorCocoa(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
GLFWbool _glfwCreateCursorCocoa(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
{
@autoreleasepool {
@ -1633,7 +1748,7 @@ int _glfwCreateCursorCocoa(_GLFWcursor* cursor,
} // autoreleasepool
}
int _glfwCreateStandardCursorCocoa(_GLFWcursor* cursor, int shape)
GLFWbool _glfwCreateStandardCursorCocoa(_GLFWcursor* cursor, int shape)
{
@autoreleasepool {
@ -1816,9 +1931,9 @@ void _glfwGetRequiredInstanceExtensionsCocoa(char** extensions)
}
}
int _glfwGetPhysicalDevicePresentationSupportCocoa(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
GLFWbool _glfwGetPhysicalDevicePresentationSupportCocoa(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
return GLFW_TRUE;
}
@ -1934,3 +2049,5 @@ GLFWAPI id glfwGetCocoaWindow(GLFWwindow* handle)
return window->ns.object;
}
#endif // _GLFW_COCOA

View File

@ -48,16 +48,6 @@
//
GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
{
if (ctxconfig->share)
{
if (ctxconfig->client == GLFW_NO_API ||
ctxconfig->share->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return GLFW_FALSE;
}
}
if (ctxconfig->source != GLFW_NATIVE_CONTEXT_API &&
ctxconfig->source != GLFW_EGL_CONTEXT_API &&
ctxconfig->source != GLFW_OSMESA_CONTEXT_API)
@ -78,6 +68,23 @@ GLFWbool _glfwIsValidContextConfig(const _GLFWctxconfig* ctxconfig)
return GLFW_FALSE;
}
if (ctxconfig->share)
{
if (ctxconfig->client == GLFW_NO_API ||
ctxconfig->share->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT, NULL);
return GLFW_FALSE;
}
if (ctxconfig->source != ctxconfig->share->context.source)
{
_glfwInputError(GLFW_INVALID_ENUM,
"Context creation APIs do not match between contexts");
return GLFW_FALSE;
}
}
if (ctxconfig->client == GLFW_OPENGL_API)
{
if ((ctxconfig->major < 1 || ctxconfig->minor < 0) ||
@ -609,10 +616,12 @@ GLFWbool _glfwStringInExtensionString(const char* string, const char* extensions
GLFWAPI void glfwMakeContextCurrent(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
_GLFWwindow* previous = _glfwPlatformGetTls(&_glfw.contextSlot);
_GLFWwindow* previous;
_GLFW_REQUIRE_INIT();
previous = _glfwPlatformGetTls(&_glfw.contextSlot);
if (window && window->context.client == GLFW_NO_API)
{
_glfwInputError(GLFW_NO_WINDOW_CONTEXT,

View File

@ -88,13 +88,30 @@ static int getEGLConfigAttrib(EGLConfig config, int attrib)
// Return the EGLConfig most closely matching the specified hints
//
static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* desired,
const _GLFWfbconfig* fbconfig,
EGLConfig* result)
{
EGLConfig* nativeConfigs;
_GLFWfbconfig* usableConfigs;
const _GLFWfbconfig* closest;
int i, nativeCount, usableCount;
int i, nativeCount, usableCount, apiBit;
GLFWbool wrongApiAvailable = GLFW_FALSE;
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
if (ctxconfig->major == 1)
apiBit = EGL_OPENGL_ES_BIT;
else
apiBit = EGL_OPENGL_ES2_BIT;
}
else
apiBit = EGL_OPENGL_BIT;
if (fbconfig->stereo)
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE, "EGL: Stereo rendering not supported");
return GLFW_FALSE;
}
eglGetConfigs(_glfw.egl.display, NULL, 0, &nativeCount);
if (!nativeCount)
@ -132,7 +149,7 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
if (!vi.visualid)
continue;
if (desired->transparent)
if (fbconfig->transparent)
{
int count;
XVisualInfo* vis =
@ -146,23 +163,10 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
}
#endif // _GLFW_X11
if (ctxconfig->client == GLFW_OPENGL_ES_API)
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & apiBit))
{
if (ctxconfig->major == 1)
{
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES_BIT))
continue;
}
else
{
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_ES2_BIT))
continue;
}
}
else if (ctxconfig->client == GLFW_OPENGL_API)
{
if (!(getEGLConfigAttrib(n, EGL_RENDERABLE_TYPE) & EGL_OPENGL_BIT))
continue;
wrongApiAvailable = GLFW_TRUE;
continue;
}
u->redBits = getEGLConfigAttrib(n, EGL_RED_SIZE);
@ -173,16 +177,60 @@ static GLFWbool chooseEGLConfig(const _GLFWctxconfig* ctxconfig,
u->depthBits = getEGLConfigAttrib(n, EGL_DEPTH_SIZE);
u->stencilBits = getEGLConfigAttrib(n, EGL_STENCIL_SIZE);
#if defined(_GLFW_WAYLAND)
if (_glfw.platform.platformID == GLFW_PLATFORM_WAYLAND)
{
// NOTE: The wl_surface opaque region is no guarantee that its buffer
// is presented as opaque, if it also has an alpha channel
// HACK: If EGL_EXT_present_opaque is unavailable, ignore any config
// with an alpha channel to ensure the buffer is opaque
if (!_glfw.egl.EXT_present_opaque)
{
if (!fbconfig->transparent && u->alphaBits > 0)
continue;
}
}
#endif // _GLFW_WAYLAND
u->samples = getEGLConfigAttrib(n, EGL_SAMPLES);
u->doublebuffer = desired->doublebuffer;
u->doublebuffer = fbconfig->doublebuffer;
u->handle = (uintptr_t) n;
usableCount++;
}
closest = _glfwChooseFBConfig(desired, usableConfigs, usableCount);
closest = _glfwChooseFBConfig(fbconfig, usableConfigs, usableCount);
if (closest)
*result = (EGLConfig) closest->handle;
else
{
if (wrongApiAvailable)
{
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
if (ctxconfig->major == 1)
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"EGL: Failed to find support for OpenGL ES 1.x");
}
else
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"EGL: Failed to find support for OpenGL ES 2 or later");
}
}
else
{
_glfwInputError(GLFW_API_UNAVAILABLE,
"EGL: Failed to find support for OpenGL");
}
}
else
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"EGL: Failed to find a suitable EGLConfig");
}
}
_glfw_free(nativeConfigs);
_glfw_free(usableConfigs);
@ -325,7 +373,7 @@ GLFWbool _glfwInitEGL(void)
"libEGL.dylib",
#elif defined(__CYGWIN__)
"libEGL-1.so",
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
"libEGL.so",
#else
"libEGL.so.1",
@ -506,7 +554,7 @@ void _glfwTerminateEGL(void)
}
}
#define setAttrib(a, v) \
#define SET_ATTRIB(a, v) \
{ \
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \
@ -535,11 +583,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
share = ctxconfig->share->context.egl.handle;
if (!chooseEGLConfig(ctxconfig, fbconfig, &config))
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"EGL: Failed to find a suitable EGLConfig");
return GLFW_FALSE;
}
if (ctxconfig->client == GLFW_OPENGL_ES_API)
{
@ -584,13 +628,13 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
{
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
{
setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
EGL_NO_RESET_NOTIFICATION_KHR);
SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
EGL_NO_RESET_NOTIFICATION_KHR);
}
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
{
setAttrib(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
EGL_LOSE_CONTEXT_ON_RESET_KHR);
SET_ATTRIB(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR,
EGL_LOSE_CONTEXT_ON_RESET_KHR);
}
flags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
@ -599,42 +643,42 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
if (ctxconfig->noerror)
{
if (_glfw.egl.KHR_create_context_no_error)
setAttrib(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
SET_ATTRIB(EGL_CONTEXT_OPENGL_NO_ERROR_KHR, GLFW_TRUE);
}
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
setAttrib(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
setAttrib(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
SET_ATTRIB(EGL_CONTEXT_MAJOR_VERSION_KHR, ctxconfig->major);
SET_ATTRIB(EGL_CONTEXT_MINOR_VERSION_KHR, ctxconfig->minor);
}
if (mask)
setAttrib(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
SET_ATTRIB(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, mask);
if (flags)
setAttrib(EGL_CONTEXT_FLAGS_KHR, flags);
SET_ATTRIB(EGL_CONTEXT_FLAGS_KHR, flags);
}
else
{
if (ctxconfig->client == GLFW_OPENGL_ES_API)
setAttrib(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
SET_ATTRIB(EGL_CONTEXT_CLIENT_VERSION, ctxconfig->major);
}
if (_glfw.egl.KHR_context_flush_control)
{
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
{
setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR);
SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR);
}
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
{
setAttrib(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
SET_ATTRIB(EGL_CONTEXT_RELEASE_BEHAVIOR_KHR,
EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR);
}
}
setAttrib(EGL_NONE, EGL_NONE);
SET_ATTRIB(EGL_NONE, EGL_NONE);
window->context.egl.handle = eglCreateContext(_glfw.egl.display,
config, share, attribs);
@ -653,16 +697,16 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
if (fbconfig->sRGB)
{
if (_glfw.egl.KHR_gl_colorspace)
setAttrib(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
SET_ATTRIB(EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR);
}
if (!fbconfig->doublebuffer)
setAttrib(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
SET_ATTRIB(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER);
if (_glfw.egl.EXT_present_opaque)
setAttrib(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent);
SET_ATTRIB(EGL_PRESENT_OPAQUE_EXT, !fbconfig->transparent);
setAttrib(EGL_NONE, EGL_NONE);
SET_ATTRIB(EGL_NONE, EGL_NONE);
native = _glfw.platform.getEGLNativeWindow(window);
// HACK: ANGLE does not implement eglCreatePlatformWindowSurfaceEXT
@ -702,7 +746,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
"libGLES_CM.dll",
#elif defined(_GLFW_COCOA)
"libGLESv1_CM.dylib",
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
"libGLESv1_CM.so",
#else
"libGLESv1_CM.so.1",
@ -721,7 +765,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
"libGLESv2.dylib",
#elif defined(__CYGWIN__)
"libGLESv2-2.so",
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
"libGLESv2.so",
#else
"libGLESv2.so.2",
@ -734,9 +778,10 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
_GLFW_OPENGL_LIBRARY,
#elif defined(_GLFW_WIN32)
#elif defined(_GLFW_COCOA)
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
"libGL.so",
#else
"libOpenGL.so.0",
"libGL.so.1",
#endif
NULL
@ -782,7 +827,7 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window,
return GLFW_TRUE;
}
#undef setAttrib
#undef SET_ATTRIB
// Returns the Visual and depth of the chosen EGLConfig
//
@ -799,11 +844,7 @@ GLFWbool _glfwChooseVisualEGL(const _GLFWwndconfig* wndconfig,
const long vimask = VisualScreenMask | VisualIDMask;
if (!chooseEGLConfig(ctxconfig, fbconfig, &native))
{
_glfwInputError(GLFW_FORMAT_UNAVAILABLE,
"EGL: Failed to find a suitable EGLConfig");
return GLFW_FALSE;
}
eglGetConfigAttrib(_glfw.egl.display, native,
EGL_NATIVE_VISUAL_ID, &visualID);

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(_GLFW_X11)
#include <string.h>
#include <stdlib.h>
#include <assert.h>
@ -226,7 +228,10 @@ static GLFWglproc getProcAddressGLX(const char* procname)
else if (_glfw.glx.GetProcAddressARB)
return _glfw.glx.GetProcAddressARB((const GLubyte*) procname);
else
{
// NOTE: glvnd provides GLX 1.4, so this can only happen with libGL
return _glfwPlatformGetModuleSymbol(_glfw.glx.handle, procname);
}
}
static void destroyContextGLX(_GLFWwindow* window)
@ -259,9 +264,10 @@ GLFWbool _glfwInitGLX(void)
_GLFW_GLX_LIBRARY,
#elif defined(__CYGWIN__)
"libGL-1.so",
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
"libGL.so",
#else
"libGLX.so.0",
"libGL.so.1",
"libGL.so",
#endif
@ -308,10 +314,6 @@ GLFWbool _glfwInitGLX(void)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXCreateWindow");
_glfw.glx.DestroyWindow = (PFNGLXDESTROYWINDOWPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXDestroyWindow");
_glfw.glx.GetProcAddress = (PFNGLXGETPROCADDRESSPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddress");
_glfw.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddressARB");
_glfw.glx.GetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetVisualFromFBConfig");
@ -327,8 +329,6 @@ GLFWbool _glfwInitGLX(void)
!_glfw.glx.CreateNewContext ||
!_glfw.glx.CreateWindow ||
!_glfw.glx.DestroyWindow ||
!_glfw.glx.GetProcAddress ||
!_glfw.glx.GetProcAddressARB ||
!_glfw.glx.GetVisualFromFBConfig)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
@ -336,6 +336,12 @@ GLFWbool _glfwInitGLX(void)
return GLFW_FALSE;
}
// NOTE: Unlike GLX 1.3 entry points these are not required to be present
_glfw.glx.GetProcAddress = (PFNGLXGETPROCADDRESSPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddress");
_glfw.glx.GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC)
_glfwPlatformGetModuleSymbol(_glfw.glx.handle, "glXGetProcAddressARB");
if (!glXQueryExtension(_glfw.x11.display,
&_glfw.glx.errorBase,
&_glfw.glx.eventBase))
@ -435,7 +441,7 @@ void _glfwTerminateGLX(void)
}
}
#define setAttrib(a, v) \
#define SET_ATTRIB(a, v) \
{ \
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \
@ -523,13 +529,13 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
{
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
{
setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
GLX_NO_RESET_NOTIFICATION_ARB);
SET_ATTRIB(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
GLX_NO_RESET_NOTIFICATION_ARB);
}
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
{
setAttrib(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
GLX_LOSE_CONTEXT_ON_RESET_ARB);
SET_ATTRIB(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
GLX_LOSE_CONTEXT_ON_RESET_ARB);
}
flags |= GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB;
@ -542,13 +548,13 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
{
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
{
setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
SET_ATTRIB(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
}
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
{
setAttrib(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
SET_ATTRIB(GLX_CONTEXT_RELEASE_BEHAVIOR_ARB,
GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
}
}
}
@ -556,7 +562,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
if (ctxconfig->noerror)
{
if (_glfw.glx.ARB_create_context_no_error)
setAttrib(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
SET_ATTRIB(GLX_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
}
// NOTE: Only request an explicitly versioned context when necessary, as
@ -564,17 +570,17 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
// highest version supported by the driver
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
setAttrib(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
setAttrib(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
SET_ATTRIB(GLX_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
SET_ATTRIB(GLX_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
}
if (mask)
setAttrib(GLX_CONTEXT_PROFILE_MASK_ARB, mask);
SET_ATTRIB(GLX_CONTEXT_PROFILE_MASK_ARB, mask);
if (flags)
setAttrib(GLX_CONTEXT_FLAGS_ARB, flags);
SET_ATTRIB(GLX_CONTEXT_FLAGS_ARB, flags);
setAttrib(None, None);
SET_ATTRIB(None, None);
window->context.glx.handle =
_glfw.glx.CreateContextAttribsARB(_glfw.x11.display,
@ -631,7 +637,7 @@ GLFWbool _glfwCreateContextGLX(_GLFWwindow* window,
return GLFW_TRUE;
}
#undef setAttrib
#undef SET_ATTRIB
// Returns the Visual and depth of the chosen GLXFBConfig
//
@ -710,3 +716,5 @@ GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* handle)
return window->context.glx.window;
}
#endif // _GLFW_X11

View File

@ -171,6 +171,59 @@ size_t _glfwEncodeUTF8(char* s, uint32_t codepoint)
return count;
}
// Splits and translates a text/uri-list into separate file paths
// NOTE: This function destroys the provided string
//
char** _glfwParseUriList(char* text, int* count)
{
const char* prefix = "file://";
char** paths = NULL;
char* line;
*count = 0;
while ((line = strtok(text, "\r\n")))
{
char* path;
text = NULL;
if (line[0] == '#')
continue;
if (strncmp(line, prefix, strlen(prefix)) == 0)
{
line += strlen(prefix);
// TODO: Validate hostname
while (*line != '/')
line++;
}
(*count)++;
path = _glfw_calloc(strlen(line) + 1, 1);
paths = _glfw_realloc(paths, *count * sizeof(char*));
paths[*count - 1] = path;
while (*line)
{
if (line[0] == '%' && line[1] && line[2])
{
const char digits[3] = { line[1], line[2], '\0' };
*path = (char) strtol(digits, NULL, 16);
line += 2;
}
else
*path = *line;
path++;
line++;
}
}
return paths;
}
char* _glfw_strdup(const char* source)
{
const size_t length = strlen(source);
@ -179,6 +232,16 @@ char* _glfw_strdup(const char* source)
return result;
}
int _glfw_min(int a, int b)
{
return a < b ? a : b;
}
int _glfw_max(int a, int b)
{
return a > b ? a : b;
}
float _glfw_fminf(float a, float b)
{
if (a != a)

View File

@ -44,6 +44,13 @@
#define _GLFW_JOYSTICK_BUTTON 2
#define _GLFW_JOYSTICK_HATBIT 3
#define GLFW_MOD_MASK (GLFW_MOD_SHIFT | \
GLFW_MOD_CONTROL | \
GLFW_MOD_ALT | \
GLFW_MOD_SUPER | \
GLFW_MOD_CAPS_LOCK | \
GLFW_MOD_NUM_LOCK)
// Initializes the platform joystick API if it has not been already
//
static GLFWbool initJoysticks(void)
@ -266,6 +273,12 @@ static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
//
void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods)
{
assert(window != NULL);
assert(key >= 0 || key == GLFW_KEY_UNKNOWN);
assert(key <= GLFW_KEY_LAST);
assert(action == GLFW_PRESS || action == GLFW_RELEASE);
assert(mods == (mods & GLFW_MOD_MASK));
if (key >= 0 && key <= GLFW_KEY_LAST)
{
GLFWbool repeated = GLFW_FALSE;
@ -297,6 +310,10 @@ void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int m
//
void _glfwInputChar(_GLFWwindow* window, uint32_t codepoint, int mods, GLFWbool plain)
{
assert(window != NULL);
assert(mods == (mods & GLFW_MOD_MASK));
assert(plain == GLFW_TRUE || plain == GLFW_FALSE);
if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
return;
@ -317,6 +334,12 @@ void _glfwInputChar(_GLFWwindow* window, uint32_t codepoint, int mods, GLFWbool
//
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
{
assert(window != NULL);
assert(xoffset > -FLT_MAX);
assert(xoffset < FLT_MAX);
assert(yoffset > -FLT_MAX);
assert(yoffset < FLT_MAX);
if (window->callbacks.scroll)
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset);
}
@ -325,6 +348,12 @@ void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
//
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
{
assert(window != NULL);
assert(button >= 0);
assert(button <= GLFW_MOUSE_BUTTON_LAST);
assert(action == GLFW_PRESS || action == GLFW_RELEASE);
assert(mods == (mods & GLFW_MOD_MASK));
if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
return;
@ -345,6 +374,12 @@ void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
//
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
{
assert(window != NULL);
assert(xpos > -FLT_MAX);
assert(xpos < FLT_MAX);
assert(ypos > -FLT_MAX);
assert(ypos < FLT_MAX);
if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos)
return;
@ -359,6 +394,9 @@ void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
//
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
{
assert(window != NULL);
assert(entered == GLFW_TRUE || entered == GLFW_FALSE);
if (window->callbacks.cursorEnter)
window->callbacks.cursorEnter((GLFWwindow*) window, entered);
}
@ -367,6 +405,10 @@ void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
//
void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
{
assert(window != NULL);
assert(count > 0);
assert(paths != NULL);
if (window->callbacks.drop)
window->callbacks.drop((GLFWwindow*) window, count, paths);
}
@ -375,16 +417,26 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
//
void _glfwInputJoystick(_GLFWjoystick* js, int event)
{
const int jid = (int) (js - _glfw.joysticks);
assert(js != NULL);
assert(event == GLFW_CONNECTED || event == GLFW_DISCONNECTED);
if (event == GLFW_CONNECTED)
js->connected = GLFW_TRUE;
else if (event == GLFW_DISCONNECTED)
js->connected = GLFW_FALSE;
if (_glfw.callbacks.joystick)
_glfw.callbacks.joystick(jid, event);
_glfw.callbacks.joystick((int) (js - _glfw.joysticks), event);
}
// Notifies shared code of the new value of a joystick axis
//
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value)
{
assert(js != NULL);
assert(axis >= 0);
assert(axis < js->axisCount);
js->axes[axis] = value;
}
@ -392,6 +444,11 @@ void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value)
//
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value)
{
assert(js != NULL);
assert(button >= 0);
assert(button < js->buttonCount);
assert(value == GLFW_PRESS || value == GLFW_RELEASE);
js->buttons[button] = value;
}
@ -399,7 +456,18 @@ void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value)
//
void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
{
const int base = js->buttonCount + hat * 4;
int base;
assert(js != NULL);
assert(hat >= 0);
assert(hat < js->hatCount);
// Valid hat values only use the least significant nibble and have at most two bits
// set, which can be considered adjacent plus an arbitrary rotation within the nibble
assert((value & 0xf0) == 0);
assert((value & ((value << 2) | (value >> 2))) == 0);
base = js->buttonCount + hat * 4;
js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE;
@ -442,7 +510,7 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name,
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (!_glfw.joysticks[jid].present)
if (!_glfw.joysticks[jid].allocated)
break;
}
@ -450,7 +518,7 @@ _GLFWjoystick* _glfwAllocJoystick(const char* name,
return NULL;
js = _glfw.joysticks + jid;
js->present = GLFW_TRUE;
js->allocated = GLFW_TRUE;
js->axes = _glfw_calloc(axisCount, sizeof(float));
js->buttons = _glfw_calloc(buttonCount + (size_t) hatCount * 4, 1);
js->hats = _glfw_calloc(hatCount, 1);
@ -528,7 +596,8 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
{
if (value != GLFW_CURSOR_NORMAL &&
value != GLFW_CURSOR_HIDDEN &&
value != GLFW_CURSOR_DISABLED)
value != GLFW_CURSOR_DISABLED &&
value != GLFW_CURSOR_CAPTURED)
{
_glfwInputError(GLFW_INVALID_ENUM,
"Invalid cursor mode 0x%08X",
@ -764,9 +833,16 @@ GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
_GLFWcursor* cursor;
assert(image != NULL);
assert(image->pixels != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (image->width <= 0 || image->height <= 0)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid image dimensions for cursor");
return NULL;
}
cursor = _glfw_calloc(1, sizeof(_GLFWcursor));
cursor->next = _glfw.cursorListHead;
_glfw.cursorListHead = cursor;
@ -965,7 +1041,7 @@ GLFWAPI int glfwJoystickPresent(int jid)
return GLFW_FALSE;
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->connected)
return GLFW_FALSE;
return _glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE);
@ -993,7 +1069,7 @@ GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count)
return NULL;
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->connected)
return NULL;
if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_AXES))
@ -1025,7 +1101,7 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count)
return NULL;
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->connected)
return NULL;
if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_BUTTONS))
@ -1061,7 +1137,7 @@ GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count)
return NULL;
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->connected)
return NULL;
if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_BUTTONS))
@ -1090,7 +1166,7 @@ GLFWAPI const char* glfwGetJoystickName(int jid)
return NULL;
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->connected)
return NULL;
if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE))
@ -1118,7 +1194,7 @@ GLFWAPI const char* glfwGetJoystickGUID(int jid)
return NULL;
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->connected)
return NULL;
if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE))
@ -1137,7 +1213,7 @@ GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer)
_GLFW_REQUIRE_INIT();
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->allocated)
return;
js->userPointer = pointer;
@ -1153,7 +1229,7 @@ GLFWAPI void* glfwGetJoystickUserPointer(int jid)
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->allocated)
return NULL;
return js->userPointer;
@ -1223,7 +1299,7 @@ GLFWAPI int glfwUpdateGamepadMappings(const char* string)
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
_GLFWjoystick* js = _glfw.joysticks + jid;
if (js->present)
if (js->connected)
js->mapping = findValidMapping(js);
}
@ -1249,7 +1325,7 @@ GLFWAPI int glfwJoystickIsGamepad(int jid)
return GLFW_FALSE;
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->connected)
return GLFW_FALSE;
if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE))
@ -1277,7 +1353,7 @@ GLFWAPI const char* glfwGetGamepadName(int jid)
return NULL;
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->connected)
return NULL;
if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE))
@ -1312,7 +1388,7 @@ GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
return GLFW_FALSE;
js = _glfw.joysticks + jid;
if (!js->present)
if (!js->connected)
return GLFW_FALSE;
if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_ALL))
@ -1421,3 +1497,4 @@ GLFWAPI uint64_t glfwGetTimerFrequency(void)
_GLFW_REQUIRE_INIT_OR_RETURN(0);
return _glfwPlatformGetTimerFrequency();
}

View File

@ -330,13 +330,6 @@ typedef VkResult (APIENTRY * PFN_vkEnumerateInstanceExtensionProperties)(const c
#include "platform.h"
// Constructs a version number string from the public header macros
#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r
#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r)
#define _GLFW_VERSION_NUMBER _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR, \
GLFW_VERSION_MINOR, \
GLFW_VERSION_REVISION)
// Checks for whether the library has been initialized
#define _GLFW_REQUIRE_INIT() \
if (!_glfw.initialized) \
@ -396,6 +389,8 @@ struct _GLFWinitconfig
//
struct _GLFWwndconfig
{
int xpos;
int ypos;
int width;
int height;
const char* title;
@ -421,6 +416,9 @@ struct _GLFWwndconfig
struct {
GLFWbool keymenu;
} win32;
struct {
char appId[256];
} wl;
};
// Context configuration
@ -634,7 +632,8 @@ struct _GLFWmapping
//
struct _GLFWjoystick
{
GLFWbool present;
GLFWbool allocated;
GLFWbool connected;
float* axes;
int axisCount;
unsigned char* buttons;
@ -680,8 +679,8 @@ struct _GLFWplatform
void (*setCursorMode)(_GLFWwindow*,int);
void (*setRawMouseMotion)(_GLFWwindow*,GLFWbool);
GLFWbool (*rawMouseMotionSupported)(void);
int (*createCursor)(_GLFWcursor*,const GLFWimage*,int,int);
int (*createStandardCursor)(_GLFWcursor*,int);
GLFWbool (*createCursor)(_GLFWcursor*,const GLFWimage*,int,int);
GLFWbool (*createStandardCursor)(_GLFWcursor*,int);
void (*destroyCursor)(_GLFWcursor*);
void (*setCursor)(_GLFWwindow*,_GLFWcursor*);
const char* (*getScancodeName)(int);
@ -690,7 +689,7 @@ struct _GLFWplatform
const char* (*getClipboardString)(void);
GLFWbool (*initJoysticks)(void);
void (*terminateJoysticks)(void);
int (*pollJoystick)(_GLFWjoystick*,int);
GLFWbool (*pollJoystick)(_GLFWjoystick*,int);
const char* (*getMappingName)(void);
void (*updateGamepadGUID)(char*);
// monitor
@ -703,7 +702,7 @@ struct _GLFWplatform
GLFWbool (*getGammaRamp)(_GLFWmonitor*,GLFWgammaramp*);
void (*setGammaRamp)(_GLFWmonitor*,const GLFWgammaramp*);
// window
int (*createWindow)(_GLFWwindow*,const _GLFWwndconfig*,const _GLFWctxconfig*,const _GLFWfbconfig*);
GLFWbool (*createWindow)(_GLFWwindow*,const _GLFWwndconfig*,const _GLFWctxconfig*,const _GLFWfbconfig*);
void (*destroyWindow)(_GLFWwindow*);
void (*setWindowTitle)(_GLFWwindow*,const char*);
void (*setWindowIcon)(_GLFWwindow*,int,const GLFWimage*);
@ -724,12 +723,12 @@ struct _GLFWplatform
void (*requestWindowAttention)(_GLFWwindow*);
void (*focusWindow)(_GLFWwindow*);
void (*setWindowMonitor)(_GLFWwindow*,_GLFWmonitor*,int,int,int,int,int);
int (*windowFocused)(_GLFWwindow*);
int (*windowIconified)(_GLFWwindow*);
int (*windowVisible)(_GLFWwindow*);
int (*windowMaximized)(_GLFWwindow*);
int (*windowHovered)(_GLFWwindow*);
int (*framebufferTransparent)(_GLFWwindow*);
GLFWbool (*windowFocused)(_GLFWwindow*);
GLFWbool (*windowIconified)(_GLFWwindow*);
GLFWbool (*windowVisible)(_GLFWwindow*);
GLFWbool (*windowMaximized)(_GLFWwindow*);
GLFWbool (*windowHovered)(_GLFWwindow*);
GLFWbool (*framebufferTransparent)(_GLFWwindow*);
float (*getWindowOpacity)(_GLFWwindow*);
void (*setWindowResizable)(_GLFWwindow*,GLFWbool);
void (*setWindowDecorated)(_GLFWwindow*,GLFWbool);
@ -746,7 +745,7 @@ struct _GLFWplatform
EGLNativeWindowType (*getEGLNativeWindow)(_GLFWwindow*);
// vulkan
void (*getRequiredInstanceExtensions)(char**);
int (*getPhysicalDevicePresentationSupport)(VkInstance,VkPhysicalDevice,uint32_t);
GLFWbool (*getPhysicalDevicePresentationSupport)(VkInstance,VkPhysicalDevice,uint32_t);
VkResult (*createWindowSurface)(VkInstance,_GLFWwindow*,const VkAllocationCallbacks*,VkSurfaceKHR*);
};
@ -996,8 +995,11 @@ void _glfwTerminateVulkan(void);
const char* _glfwGetVulkanResultString(VkResult result);
size_t _glfwEncodeUTF8(char* s, uint32_t codepoint);
char** _glfwParseUriList(char* text, int* count);
char* _glfw_strdup(const char* source);
int _glfw_min(int a, int b);
int _glfw_max(int a, int b);
float _glfw_fminf(float a, float b);
float _glfw_fmaxf(float a, float b);

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/inotify.h>
@ -128,7 +130,7 @@ static GLFWbool openJoystickDevice(const char* path)
{
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (!_glfw.joysticks[jid].present)
if (!_glfw.joysticks[jid].connected)
continue;
if (strcmp(_glfw.joysticks[jid].linjs.path, path) == 0)
return GLFW_FALSE;
@ -157,7 +159,7 @@ static GLFWbool openJoystickDevice(const char* path)
}
// Ensure this device supports the events expected of a joystick
if (!isBitSet(EV_KEY, evBits) || !isBitSet(EV_ABS, evBits))
if (!isBitSet(EV_ABS, evBits))
{
close(linjs.fd);
return GLFW_FALSE;
@ -245,9 +247,9 @@ static GLFWbool openJoystickDevice(const char* path)
//
static void closeJoystick(_GLFWjoystick* js)
{
_glfwInputJoystick(js, GLFW_DISCONNECTED);
close(js->linjs.fd);
_glfwFreeJoystick(js);
_glfwInputJoystick(js, GLFW_DISCONNECTED);
}
// Lexically compare joysticks by name; used by qsort
@ -366,7 +368,7 @@ void _glfwTerminateJoysticksLinux(void)
for (int jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
_GLFWjoystick* js = _glfw.joysticks + jid;
if (js->present)
if (js->connected)
closeJoystick(js);
}
@ -380,7 +382,7 @@ void _glfwTerminateJoysticksLinux(void)
}
}
int _glfwPollJoystickLinux(_GLFWjoystick* js, int mode)
GLFWbool _glfwPollJoystickLinux(_GLFWjoystick* js, int mode)
{
// Read all queued events (non-blocking)
for (;;)
@ -417,7 +419,7 @@ int _glfwPollJoystickLinux(_GLFWjoystick* js, int mode)
handleAbsEvent(js, e.code, e.value);
}
return js->present;
return js->connected;
}
const char* _glfwGetMappingNameLinux(void)
@ -429,3 +431,5 @@ void _glfwUpdateGamepadGUIDLinux(char* guid)
{
}
#endif // GLFW_BUILD_LINUX_JOYSTICK

View File

@ -31,8 +31,6 @@
#define GLFW_LINUX_JOYSTICK_STATE _GLFWjoystickLinux linjs;
#define GLFW_LINUX_LIBRARY_JOYSTICK_STATE _GLFWlibraryLinux linjs;
#define GLFW_BUILD_LINUX_MAPPINGS
// Linux-specific joystick data
//
typedef struct _GLFWjoystickLinux
@ -59,7 +57,7 @@ void _glfwDetectJoystickConnectionLinux(void);
GLFWbool _glfwInitJoysticksLinux(void);
void _glfwTerminateJoysticksLinux(void);
int _glfwPollJoystickLinux(_GLFWjoystick* js, int mode);
GLFWbool _glfwPollJoystickLinux(_GLFWjoystick* js, int mode);
const char* _glfwGetMappingNameLinux(void);
void _glfwUpdateGamepadGUIDLinux(char* guid);

View File

@ -60,7 +60,7 @@
const char* _glfwDefaultMappings[] =
{
#if defined(GLFW_BUILD_WIN32_MAPPINGS)
#if defined(_GLFW_WIN32)
"03000000fa2d00000100000000000000,3DRUDDER,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows,",
"03000000c82d00002038000000000000,8bitdo,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows,",
"03000000c82d00000951000000000000,8BitDo Dogbone Modkit,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,",
@ -426,9 +426,9 @@ const char* _glfwDefaultMappings[] =
"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
#endif // GLFW_BUILD_WIN32_MAPPINGS
#endif // _GLFW_WIN32
#if defined(GLFW_BUILD_COCOA_MAPPINGS)
#if defined(_GLFW_COCOA)
"030000008f0e00000300000009010000,2In1 USB Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,",
"03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
"03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,",
@ -598,9 +598,9 @@ const char* _glfwDefaultMappings[] =
"03000000172700004431000029010000,XiaoMi Game Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,",
"03000000120c0000100e000000010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
"03000000120c0000101e000000010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,",
#endif // GLFW_BUILD_COCOA_MAPPINGS
#endif // _GLFW_COCOA
#if defined(GLFW_BUILD_LINUX_MAPPINGS)
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
"03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
"05000000c82d00001038000000010000,8Bitdo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,",
"05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,",
@ -996,6 +996,6 @@ const char* _glfwDefaultMappings[] =
"03000000c0160000e105000001010000,Xin-Mo Xin-Mo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux,",
"03000000120c0000100e000011010000,ZEROPLUS P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
"03000000120c0000101e000011010000,ZEROPLUS P4 Wired Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,",
#endif // GLFW_BUILD_LINUX_MAPPINGS
#endif // GLFW_BUILD_LINUX_JOYSTICK
};

View File

@ -60,7 +60,7 @@
const char* _glfwDefaultMappings[] =
{
#if defined(GLFW_BUILD_WIN32_MAPPINGS)
#if defined(_GLFW_WIN32)
@GLFW_WIN32_MAPPINGS@
"78696e70757401000000000000000000,XInput Gamepad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757402000000000000000000,XInput Wheel (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
@ -69,14 +69,14 @@ const char* _glfwDefaultMappings[] =
"78696e70757405000000000000000000,XInput Dance Pad (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757406000000000000000000,XInput Guitar (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
"78696e70757408000000000000000000,XInput Drum Kit (GLFW),platform:Windows,a:b0,b:b1,x:b2,y:b3,leftshoulder:b4,rightshoulder:b5,back:b6,start:b7,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,dpup:h0.1,dpright:h0.2,dpdown:h0.4,dpleft:h0.8,",
#endif // GLFW_BUILD_WIN32_MAPPINGS
#endif // _GLFW_WIN32
#if defined(GLFW_BUILD_COCOA_MAPPINGS)
#if defined(_GLFW_COCOA)
@GLFW_COCOA_MAPPINGS@
#endif // GLFW_BUILD_COCOA_MAPPINGS
#endif // _GLFW_COCOA
#if defined(GLFW_BUILD_LINUX_MAPPINGS)
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
@GLFW_LINUX_MAPPINGS@
#endif // GLFW_BUILD_LINUX_MAPPINGS
#endif // GLFW_BUILD_LINUX_JOYSTICK
};

View File

@ -96,6 +96,10 @@ static GLFWbool refreshVideoModes(_GLFWmonitor* monitor)
//
void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
{
assert(monitor != NULL);
assert(action == GLFW_CONNECTED || action == GLFW_DISCONNECTED);
assert(placement == _GLFW_INSERT_FIRST || placement == _GLFW_INSERT_LAST);
if (action == GLFW_CONNECTED)
{
_glfw.monitorCount++;
@ -155,6 +159,7 @@ void _glfwInputMonitor(_GLFWmonitor* monitor, int action, int placement)
//
void _glfwInputMonitorWindow(_GLFWmonitor* monitor, _GLFWwindow* window)
{
assert(monitor != NULL);
monitor->window = window;
}
@ -522,6 +527,8 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
assert(ramp->green != NULL);
assert(ramp->blue != NULL);
_GLFW_REQUIRE_INIT();
if (ramp->size <= 0)
{
_glfwInputError(GLFW_INVALID_VALUE,
@ -530,8 +537,6 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* handle, const GLFWgammaramp* ramp)
return;
}
_GLFW_REQUIRE_INIT();
if (!monitor->originalRamp.size)
{
if (!_glfw.platform.getGammaRamp(monitor, &monitor->originalRamp))

View File

@ -28,6 +28,8 @@
#include "internal.h"
#if defined(_GLFW_COCOA)
#include <unistd.h>
#include <math.h>
@ -188,45 +190,45 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
// No-error contexts (GL_KHR_no_error) are not yet supported by macOS but
// are not a hard constraint, so ignore and continue
#define addAttrib(a) \
#define ADD_ATTRIB(a) \
{ \
assert((size_t) index < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \
}
#define setAttrib(a, v) { addAttrib(a); addAttrib(v); }
#define SET_ATTRIB(a, v) { ADD_ATTRIB(a); ADD_ATTRIB(v); }
NSOpenGLPixelFormatAttribute attribs[40];
int index = 0;
addAttrib(NSOpenGLPFAAccelerated);
addAttrib(NSOpenGLPFAClosestPolicy);
ADD_ATTRIB(NSOpenGLPFAAccelerated);
ADD_ATTRIB(NSOpenGLPFAClosestPolicy);
if (ctxconfig->nsgl.offline)
{
addAttrib(NSOpenGLPFAAllowOfflineRenderers);
ADD_ATTRIB(NSOpenGLPFAAllowOfflineRenderers);
// NOTE: This replaces the NSSupportsAutomaticGraphicsSwitching key in
// Info.plist for unbundled applications
// HACK: This assumes that NSOpenGLPixelFormat will remain
// a straightforward wrapper of its CGL counterpart
addAttrib(kCGLPFASupportsAutomaticGraphicsSwitching);
ADD_ATTRIB(kCGLPFASupportsAutomaticGraphicsSwitching);
}
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
if (ctxconfig->major >= 4)
{
setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion4_1Core);
}
else
#endif /*MAC_OS_X_VERSION_MAX_ALLOWED*/
if (ctxconfig->major >= 3)
{
setAttrib(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
SET_ATTRIB(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core);
}
if (ctxconfig->major <= 2)
{
if (fbconfig->auxBuffers != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
SET_ATTRIB(NSOpenGLPFAAuxBuffers, fbconfig->auxBuffers);
if (fbconfig->accumRedBits != GLFW_DONT_CARE &&
fbconfig->accumGreenBits != GLFW_DONT_CARE &&
@ -238,7 +240,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
fbconfig->accumBlueBits +
fbconfig->accumAlphaBits;
setAttrib(NSOpenGLPFAAccumSize, accumBits);
SET_ATTRIB(NSOpenGLPFAAccumSize, accumBits);
}
}
@ -256,17 +258,17 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
else if (colorBits < 15)
colorBits = 15;
setAttrib(NSOpenGLPFAColorSize, colorBits);
SET_ATTRIB(NSOpenGLPFAColorSize, colorBits);
}
if (fbconfig->alphaBits != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
SET_ATTRIB(NSOpenGLPFAAlphaSize, fbconfig->alphaBits);
if (fbconfig->depthBits != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFADepthSize, fbconfig->depthBits);
SET_ATTRIB(NSOpenGLPFADepthSize, fbconfig->depthBits);
if (fbconfig->stencilBits != GLFW_DONT_CARE)
setAttrib(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
SET_ATTRIB(NSOpenGLPFAStencilSize, fbconfig->stencilBits);
if (fbconfig->stereo)
{
@ -275,33 +277,33 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
"NSGL: Stereo rendering is deprecated");
return GLFW_FALSE;
#else
addAttrib(NSOpenGLPFAStereo);
ADD_ATTRIB(NSOpenGLPFAStereo);
#endif
}
if (fbconfig->doublebuffer)
addAttrib(NSOpenGLPFADoubleBuffer);
ADD_ATTRIB(NSOpenGLPFADoubleBuffer);
if (fbconfig->samples != GLFW_DONT_CARE)
{
if (fbconfig->samples == 0)
{
setAttrib(NSOpenGLPFASampleBuffers, 0);
SET_ATTRIB(NSOpenGLPFASampleBuffers, 0);
}
else
{
setAttrib(NSOpenGLPFASampleBuffers, 1);
setAttrib(NSOpenGLPFASamples, fbconfig->samples);
SET_ATTRIB(NSOpenGLPFASampleBuffers, 1);
SET_ATTRIB(NSOpenGLPFASamples, fbconfig->samples);
}
}
// NOTE: All NSOpenGLPixelFormats on the relevant cards support sRGB
// framebuffer, so there's no need (and no way) to request it
addAttrib(0);
ADD_ATTRIB(0);
#undef addAttrib
#undef setAttrib
#undef ADD_ATTRIB
#undef SET_ATTRIB
window->context.nsgl.pixelFormat =
[[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
@ -374,3 +376,5 @@ GLFWAPI id glfwGetNSGLContext(GLFWwindow* handle)
return window->context.nsgl.object;
}
#endif // _GLFW_COCOA

View File

@ -42,7 +42,7 @@ void _glfwTerminateJoysticksNull(void)
{
}
int _glfwPollJoystickNull(_GLFWjoystick* js, int mode)
GLFWbool _glfwPollJoystickNull(_GLFWjoystick* js, int mode)
{
return GLFW_FALSE;
}

View File

@ -26,7 +26,7 @@
GLFWbool _glfwInitJoysticksNull(void);
void _glfwTerminateJoysticksNull(void);
int _glfwPollJoystickNull(_GLFWjoystick* js, int mode);
GLFWbool _glfwPollJoystickNull(_GLFWjoystick* js, int mode);
const char* _glfwGetMappingNameNull(void);
void _glfwUpdateGamepadGUIDNull(char* guid);

View File

@ -85,7 +85,7 @@ void _glfwGetVideoModeNull(_GLFWmonitor* monitor, GLFWvidmode* mode);
GLFWbool _glfwGetGammaRampNull(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
void _glfwSetGammaRampNull(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
int _glfwCreateWindowNull(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
GLFWbool _glfwCreateWindowNull(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
void _glfwDestroyWindowNull(_GLFWwindow* window);
void _glfwSetWindowTitleNull(_GLFWwindow* window, const char* title);
void _glfwSetWindowIconNull(_GLFWwindow* window, int count, const GLFWimage* images);
@ -102,9 +102,9 @@ void _glfwGetWindowContentScaleNull(_GLFWwindow* window, float* xscale, float* y
void _glfwIconifyWindowNull(_GLFWwindow* window);
void _glfwRestoreWindowNull(_GLFWwindow* window);
void _glfwMaximizeWindowNull(_GLFWwindow* window);
int _glfwWindowMaximizedNull(_GLFWwindow* window);
int _glfwWindowHoveredNull(_GLFWwindow* window);
int _glfwFramebufferTransparentNull(_GLFWwindow* window);
GLFWbool _glfwWindowMaximizedNull(_GLFWwindow* window);
GLFWbool _glfwWindowHoveredNull(_GLFWwindow* window);
GLFWbool _glfwFramebufferTransparentNull(_GLFWwindow* window);
void _glfwSetWindowResizableNull(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowDecoratedNull(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowFloatingNull(_GLFWwindow* window, GLFWbool enabled);
@ -118,9 +118,9 @@ void _glfwRequestWindowAttentionNull(_GLFWwindow* window);
void _glfwRequestWindowAttentionNull(_GLFWwindow* window);
void _glfwHideWindowNull(_GLFWwindow* window);
void _glfwFocusWindowNull(_GLFWwindow* window);
int _glfwWindowFocusedNull(_GLFWwindow* window);
int _glfwWindowIconifiedNull(_GLFWwindow* window);
int _glfwWindowVisibleNull(_GLFWwindow* window);
GLFWbool _glfwWindowFocusedNull(_GLFWwindow* window);
GLFWbool _glfwWindowIconifiedNull(_GLFWwindow* window);
GLFWbool _glfwWindowVisibleNull(_GLFWwindow* window);
void _glfwPollEventsNull(void);
void _glfwWaitEventsNull(void);
void _glfwWaitEventsTimeoutNull(double timeout);
@ -128,8 +128,8 @@ void _glfwPostEmptyEventNull(void);
void _glfwGetCursorPosNull(_GLFWwindow* window, double* xpos, double* ypos);
void _glfwSetCursorPosNull(_GLFWwindow* window, double x, double y);
void _glfwSetCursorModeNull(_GLFWwindow* window, int mode);
int _glfwCreateCursorNull(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
int _glfwCreateStandardCursorNull(_GLFWcursor* cursor, int shape);
GLFWbool _glfwCreateCursorNull(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
GLFWbool _glfwCreateStandardCursorNull(_GLFWcursor* cursor, int shape);
void _glfwDestroyCursorNull(_GLFWcursor* cursor);
void _glfwSetCursorNull(_GLFWwindow* window, _GLFWcursor* cursor);
void _glfwSetClipboardStringNull(const char* string);
@ -142,7 +142,7 @@ EGLNativeDisplayType _glfwGetEGLNativeDisplayNull(void);
EGLNativeWindowType _glfwGetEGLNativeWindowNull(_GLFWwindow* window);
void _glfwGetRequiredInstanceExtensionsNull(char** extensions);
int _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
GLFWbool _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceNull(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
void _glfwPollMonitorsNull(void);

View File

@ -39,15 +39,15 @@ static void applySizeLimits(_GLFWwindow* window, int* width, int* height)
*height = (int) (*width / ratio);
}
if (window->minwidth != GLFW_DONT_CARE && *width < window->minwidth)
*width = window->minwidth;
else if (window->maxwidth != GLFW_DONT_CARE && *width > window->maxwidth)
*width = window->maxwidth;
if (window->minwidth != GLFW_DONT_CARE)
*width = _glfw_max(*width, window->minwidth);
else if (window->maxwidth != GLFW_DONT_CARE)
*width = _glfw_min(*width, window->maxwidth);
if (window->minheight != GLFW_DONT_CARE && *height < window->minheight)
*height = window->minheight;
else if (window->maxheight != GLFW_DONT_CARE && *height > window->maxheight)
*height = window->maxheight;
if (window->minheight != GLFW_DONT_CARE)
*height = _glfw_min(*height, window->minheight);
else if (window->maxheight != GLFW_DONT_CARE)
*height = _glfw_max(*height, window->maxheight);
}
static void fitToMonitor(_GLFWwindow* window)
@ -82,8 +82,17 @@ static int createNativeWindow(_GLFWwindow* window,
fitToMonitor(window);
else
{
window->null.xpos = 17;
window->null.ypos = 17;
if (wndconfig->xpos == GLFW_ANY_POSITION && wndconfig->ypos == GLFW_ANY_POSITION)
{
window->null.xpos = 17;
window->null.ypos = 17;
}
else
{
window->null.xpos = wndconfig->xpos;
window->null.ypos = wndconfig->ypos;
}
window->null.width = wndconfig->width;
window->null.height = wndconfig->height;
}
@ -103,10 +112,10 @@ static int createNativeWindow(_GLFWwindow* window,
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwCreateWindowNull(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
GLFWbool _glfwCreateWindowNull(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (!createNativeWindow(window, wndconfig, fbconfig))
return GLFW_FALSE;
@ -128,13 +137,31 @@ int _glfwCreateWindowNull(_GLFWwindow* window,
if (!_glfwCreateContextEGL(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
}
if (wndconfig->mousePassthrough)
_glfwSetWindowMousePassthroughNull(window, GLFW_TRUE);
if (window->monitor)
{
_glfwShowWindowNull(window);
_glfwFocusWindowNull(window);
acquireMonitor(window);
if (wndconfig->centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig->visible)
{
_glfwShowWindowNull(window);
if (wndconfig->focused)
_glfwFocusWindowNull(window);
}
}
return GLFW_TRUE;
@ -344,12 +371,12 @@ void _glfwMaximizeWindowNull(_GLFWwindow* window)
}
}
int _glfwWindowMaximizedNull(_GLFWwindow* window)
GLFWbool _glfwWindowMaximizedNull(_GLFWwindow* window)
{
return window->null.maximized;
}
int _glfwWindowHoveredNull(_GLFWwindow* window)
GLFWbool _glfwWindowHoveredNull(_GLFWwindow* window)
{
return _glfw.null.xcursor >= window->null.xpos &&
_glfw.null.ycursor >= window->null.ypos &&
@ -357,7 +384,7 @@ int _glfwWindowHoveredNull(_GLFWwindow* window)
_glfw.null.ycursor <= window->null.ypos + window->null.height - 1;
}
int _glfwFramebufferTransparentNull(_GLFWwindow* window)
GLFWbool _glfwFramebufferTransparentNull(_GLFWwindow* window)
{
return window->null.transparent;
}
@ -443,17 +470,17 @@ void _glfwFocusWindowNull(_GLFWwindow* window)
_glfwInputWindowFocus(window, GLFW_TRUE);
}
int _glfwWindowFocusedNull(_GLFWwindow* window)
GLFWbool _glfwWindowFocusedNull(_GLFWwindow* window)
{
return _glfw.null.focusedWindow == window;
}
int _glfwWindowIconifiedNull(_GLFWwindow* window)
GLFWbool _glfwWindowIconifiedNull(_GLFWwindow* window)
{
return window->null.iconified;
}
int _glfwWindowVisibleNull(_GLFWwindow* window)
GLFWbool _glfwWindowVisibleNull(_GLFWwindow* window)
{
return window->null.visible;
}
@ -492,14 +519,14 @@ void _glfwSetCursorModeNull(_GLFWwindow* window, int mode)
{
}
int _glfwCreateCursorNull(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
GLFWbool _glfwCreateCursorNull(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
{
return GLFW_TRUE;
}
int _glfwCreateStandardCursorNull(_GLFWcursor* cursor, int shape)
GLFWbool _glfwCreateStandardCursorNull(_GLFWcursor* cursor, int shape)
{
return GLFW_TRUE;
}
@ -675,9 +702,9 @@ void _glfwGetRequiredInstanceExtensionsNull(char** extensions)
{
}
int _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
GLFWbool _glfwGetPhysicalDevicePresentationSupportNull(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
return GLFW_FALSE;
}

View File

@ -124,7 +124,7 @@ GLFWbool _glfwInitOSMesa(void)
"libOSMesa.8.dylib",
#elif defined(__CYGWIN__)
"libOSMesa-8.so",
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
"libOSMesa.so",
#else
"libOSMesa.so.8",
@ -190,7 +190,7 @@ void _glfwTerminateOSMesa(void)
}
}
#define setAttrib(a, v) \
#define SET_ATTRIB(a, v) \
{ \
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \
@ -221,24 +221,24 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
{
int index = 0, attribs[40];
setAttrib(OSMESA_FORMAT, OSMESA_RGBA);
setAttrib(OSMESA_DEPTH_BITS, fbconfig->depthBits);
setAttrib(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
setAttrib(OSMESA_ACCUM_BITS, accumBits);
SET_ATTRIB(OSMESA_FORMAT, OSMESA_RGBA);
SET_ATTRIB(OSMESA_DEPTH_BITS, fbconfig->depthBits);
SET_ATTRIB(OSMESA_STENCIL_BITS, fbconfig->stencilBits);
SET_ATTRIB(OSMESA_ACCUM_BITS, accumBits);
if (ctxconfig->profile == GLFW_OPENGL_CORE_PROFILE)
{
setAttrib(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
SET_ATTRIB(OSMESA_PROFILE, OSMESA_CORE_PROFILE);
}
else if (ctxconfig->profile == GLFW_OPENGL_COMPAT_PROFILE)
{
setAttrib(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
SET_ATTRIB(OSMESA_PROFILE, OSMESA_COMPAT_PROFILE);
}
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
setAttrib(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
setAttrib(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
SET_ATTRIB(OSMESA_CONTEXT_MAJOR_VERSION, ctxconfig->major);
SET_ATTRIB(OSMESA_CONTEXT_MINOR_VERSION, ctxconfig->minor);
}
if (ctxconfig->forward)
@ -248,7 +248,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
return GLFW_FALSE;
}
setAttrib(0, 0);
SET_ATTRIB(0, 0);
window->context.osmesa.handle =
OSMesaCreateContextAttribs(attribs, share);
@ -287,7 +287,7 @@ GLFWbool _glfwCreateContextOSMesa(_GLFWwindow* window,
return GLFW_TRUE;
}
#undef setAttrib
#undef SET_ATTRIB
//////////////////////////////////////////////////////////////////////////

View File

@ -29,6 +29,10 @@
#include "internal.h"
// These construct a string literal from individual numeric constants
#define _GLFW_CONCAT_VERSION(m, n, r) #m "." #n "." #r
#define _GLFW_MAKE_VERSION(m, n, r) _GLFW_CONCAT_VERSION(m, n, r)
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
@ -146,7 +150,9 @@ GLFWAPI int glfwPlatformSupported(int platformID)
GLFWAPI const char* glfwGetVersionString(void)
{
return _GLFW_VERSION_NUMBER
return _GLFW_MAKE_VERSION(GLFW_VERSION_MAJOR,
GLFW_VERSION_MINOR,
GLFW_VERSION_REVISION)
#if defined(_GLFW_WIN32)
" Win32 WGL"
#endif

View File

@ -25,6 +25,18 @@
//
//========================================================================
#if defined(GLFW_BUILD_WIN32_TIMER) || \
defined(GLFW_BUILD_WIN32_MODULE) || \
defined(GLFW_BUILD_WIN32_THREAD) || \
defined(GLFW_BUILD_COCOA_TIMER) || \
defined(GLFW_BUILD_POSIX_TIMER) || \
defined(GLFW_BUILD_POSIX_MODULE) || \
defined(GLFW_BUILD_POSIX_THREAD) || \
defined(GLFW_BUILD_POSIX_POLL) || \
defined(GLFW_BUILD_LINUX_JOYSTICK)
#error "You must not define these; define zero or more _GLFW_<platform> macros instead"
#endif
#include "null_platform.h"
#if defined(_GLFW_WIN32)
@ -86,36 +98,16 @@
#endif
#if (defined(_GLFW_X11) || defined(_GLFW_WAYLAND)) && defined(__linux__)
#define GLFW_BUILD_LINUX_JOYSTICK
#endif
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
#include "linux_joystick.h"
#else
#define GLFW_LINUX_JOYSTICK_STATE
#define GLFW_LINUX_LIBRARY_JOYSTICK_STATE
#endif
#if defined(_WIN32)
#include "win32_thread.h"
#define GLFW_POSIX_TLS_STATE
#define GLFW_POSIX_MUTEX_STATE
#else
#include "posix_thread.h"
#define GLFW_WIN32_TLS_STATE
#define GLFW_WIN32_MUTEX_STATE
#endif
#if defined(_WIN32)
#include "win32_time.h"
#define GLFW_POSIX_LIBRARY_TIMER_STATE
#define GLFW_COCOA_LIBRARY_TIMER_STATE
#elif defined(__APPLE__)
#include "cocoa_time.h"
#define GLFW_WIN32_LIBRARY_TIMER_STATE
#define GLFW_POSIX_LIBRARY_TIMER_STATE
#else
#include "posix_time.h"
#define GLFW_WIN32_LIBRARY_TIMER_STATE
#define GLFW_COCOA_LIBRARY_TIMER_STATE
#endif
#define GLFW_PLATFORM_WINDOW_STATE \
GLFW_WIN32_WINDOW_STATE \
GLFW_COCOA_WINDOW_STATE \
@ -142,14 +134,6 @@
GLFW_COCOA_JOYSTICK_STATE \
GLFW_LINUX_JOYSTICK_STATE
#define GLFW_PLATFORM_TLS_STATE \
GLFW_WIN32_TLS_STATE \
GLFW_POSIX_TLS_STATE \
#define GLFW_PLATFORM_MUTEX_STATE \
GLFW_WIN32_MUTEX_STATE \
GLFW_POSIX_MUTEX_STATE \
#define GLFW_PLATFORM_LIBRARY_WINDOW_STATE \
GLFW_WIN32_LIBRARY_WINDOW_STATE \
GLFW_COCOA_LIBRARY_WINDOW_STATE \
@ -162,11 +146,6 @@
GLFW_COCOA_LIBRARY_JOYSTICK_STATE \
GLFW_LINUX_LIBRARY_JOYSTICK_STATE
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE \
GLFW_WIN32_LIBRARY_TIMER_STATE \
GLFW_COCOA_LIBRARY_TIMER_STATE \
GLFW_POSIX_LIBRARY_TIMER_STATE \
#define GLFW_PLATFORM_CONTEXT_STATE \
GLFW_WGL_CONTEXT_STATE \
GLFW_NSGL_CONTEXT_STATE \
@ -177,3 +156,48 @@
GLFW_NSGL_LIBRARY_CONTEXT_STATE \
GLFW_GLX_LIBRARY_CONTEXT_STATE
#if defined(_WIN32)
#define GLFW_BUILD_WIN32_THREAD
#else
#define GLFW_BUILD_POSIX_THREAD
#endif
#if defined(GLFW_BUILD_WIN32_THREAD)
#include "win32_thread.h"
#define GLFW_PLATFORM_TLS_STATE GLFW_WIN32_TLS_STATE
#define GLFW_PLATFORM_MUTEX_STATE GLFW_WIN32_MUTEX_STATE
#elif defined(GLFW_BUILD_POSIX_THREAD)
#include "posix_thread.h"
#define GLFW_PLATFORM_TLS_STATE GLFW_POSIX_TLS_STATE
#define GLFW_PLATFORM_MUTEX_STATE GLFW_POSIX_MUTEX_STATE
#endif
#if defined(_WIN32)
#define GLFW_BUILD_WIN32_TIMER
#elif defined(__APPLE__)
#define GLFW_BUILD_COCOA_TIMER
#else
#define GLFW_BUILD_POSIX_TIMER
#endif
#if defined(GLFW_BUILD_WIN32_TIMER)
#include "win32_time.h"
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_WIN32_LIBRARY_TIMER_STATE
#elif defined(GLFW_BUILD_COCOA_TIMER)
#include "cocoa_time.h"
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_COCOA_LIBRARY_TIMER_STATE
#elif defined(GLFW_BUILD_POSIX_TIMER)
#include "posix_time.h"
#define GLFW_PLATFORM_LIBRARY_TIMER_STATE GLFW_POSIX_LIBRARY_TIMER_STATE
#endif
#if defined(_WIN32)
#define GLFW_BUILD_WIN32_MODULE
#else
#define GLFW_BUILD_POSIX_MODULE
#endif
#if defined(_GLFW_WAYLAND) || defined(_GLFW_X11)
#define GLFW_BUILD_POSIX_POLL
#endif

View File

@ -28,6 +28,8 @@
#include "internal.h"
#if defined(GLFW_BUILD_POSIX_MODULE)
#include <dlfcn.h>
//////////////////////////////////////////////////////////////////////////
@ -49,3 +51,5 @@ GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name)
return dlsym(module, name);
}
#endif // GLFW_BUILD_POSIX_MODULE

85
thirdparty/glfw/src/posix_poll.c vendored Normal file
View File

@ -0,0 +1,85 @@
//========================================================================
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2022 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#define _GNU_SOURCE
#include "internal.h"
#if defined(GLFW_BUILD_POSIX_POLL)
#include <signal.h>
#include <time.h>
#include <errno.h>
GLFWbool _glfwPollPOSIX(struct pollfd* fds, nfds_t count, double* timeout)
{
for (;;)
{
if (timeout)
{
const uint64_t base = _glfwPlatformGetTimerValue();
#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__CYGWIN__)
const time_t seconds = (time_t) *timeout;
const long nanoseconds = (long) ((*timeout - seconds) * 1e9);
const struct timespec ts = { seconds, nanoseconds };
const int result = ppoll(fds, count, &ts, NULL);
#elif defined(__NetBSD__)
const time_t seconds = (time_t) *timeout;
const long nanoseconds = (long) ((*timeout - seconds) * 1e9);
const struct timespec ts = { seconds, nanoseconds };
const int result = pollts(fds, count, &ts, NULL);
#else
const int milliseconds = (int) (*timeout * 1e3);
const int result = poll(fds, count, milliseconds);
#endif
const int error = errno; // clock_gettime may overwrite our error
*timeout -= (_glfwPlatformGetTimerValue() - base) /
(double) _glfwPlatformGetTimerFrequency();
if (result > 0)
return GLFW_TRUE;
else if (result == -1 && error != EINTR && error != EAGAIN)
return GLFW_FALSE;
else if (*timeout <= 0.0)
return GLFW_FALSE;
}
else
{
const int result = poll(fds, count, -1);
if (result > 0)
return GLFW_TRUE;
else if (result == -1 && errno != EINTR && errno != EAGAIN)
return GLFW_FALSE;
}
}
}
#endif // GLFW_BUILD_POSIX_POLL

32
thirdparty/glfw/src/posix_poll.h vendored Normal file
View File

@ -0,0 +1,32 @@
//========================================================================
// GLFW 3.4 POSIX - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2022 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
// It is fine to use C99 in this file because it will not be built with VS
//========================================================================
#include <poll.h>
GLFWbool _glfwPollPOSIX(struct pollfd* fds, nfds_t count, double* timeout);

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(GLFW_BUILD_POSIX_THREAD)
#include <assert.h>
#include <string.h>
@ -103,3 +105,5 @@ void _glfwPlatformUnlockMutex(_GLFWmutex* mutex)
pthread_mutex_unlock(&mutex->posix.handle);
}
#endif // GLFW_BUILD_POSIX_THREAD

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(GLFW_BUILD_POSIX_TIMER)
#include <unistd.h>
#include <sys/time.h>
@ -61,3 +63,5 @@ uint64_t _glfwPlatformGetTimerFrequency(void)
return _glfw.timer.posix.frequency;
}
#endif // GLFW_BUILD_POSIX_TIMER

View File

@ -63,7 +63,7 @@ GLFWbool _glfwInitVulkan(int mode)
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib");
if (!_glfw.vk.handle)
_glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa();
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so");
#else
_glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so.1");

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(_GLFW_WIN32)
#include <stdlib.h>
#include <assert.h>
@ -52,12 +54,12 @@ static int findPixelFormatAttribValueWGL(const int* attribs,
return 0;
}
#define addAttrib(a) \
#define ADD_ATTRIB(a) \
{ \
assert((size_t) attribCount < sizeof(attribs) / sizeof(attribs[0])); \
attribs[attribCount++] = a; \
}
#define findAttribValue(a) \
#define FIND_ATTRIB_VALUE(a) \
findPixelFormatAttribValueWGL(attribs, attribCount, values, a)
// Return a list of available and usable framebuffer configs
@ -72,62 +74,50 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
int attribs[40];
int values[sizeof(attribs) / sizeof(attribs[0])];
nativeCount = DescribePixelFormat(window->context.wgl.dc,
1,
sizeof(PIXELFORMATDESCRIPTOR),
NULL);
if (_glfw.wgl.ARB_pixel_format)
{
const int attrib = WGL_NUMBER_PIXEL_FORMATS_ARB;
if (!wglGetPixelFormatAttribivARB(window->context.wgl.dc,
1, 0, 1, &attrib, &nativeCount))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WGL: Failed to retrieve pixel format attribute");
return 0;
}
addAttrib(WGL_SUPPORT_OPENGL_ARB);
addAttrib(WGL_DRAW_TO_WINDOW_ARB);
addAttrib(WGL_PIXEL_TYPE_ARB);
addAttrib(WGL_ACCELERATION_ARB);
addAttrib(WGL_RED_BITS_ARB);
addAttrib(WGL_RED_SHIFT_ARB);
addAttrib(WGL_GREEN_BITS_ARB);
addAttrib(WGL_GREEN_SHIFT_ARB);
addAttrib(WGL_BLUE_BITS_ARB);
addAttrib(WGL_BLUE_SHIFT_ARB);
addAttrib(WGL_ALPHA_BITS_ARB);
addAttrib(WGL_ALPHA_SHIFT_ARB);
addAttrib(WGL_DEPTH_BITS_ARB);
addAttrib(WGL_STENCIL_BITS_ARB);
addAttrib(WGL_ACCUM_BITS_ARB);
addAttrib(WGL_ACCUM_RED_BITS_ARB);
addAttrib(WGL_ACCUM_GREEN_BITS_ARB);
addAttrib(WGL_ACCUM_BLUE_BITS_ARB);
addAttrib(WGL_ACCUM_ALPHA_BITS_ARB);
addAttrib(WGL_AUX_BUFFERS_ARB);
addAttrib(WGL_STEREO_ARB);
addAttrib(WGL_DOUBLE_BUFFER_ARB);
ADD_ATTRIB(WGL_SUPPORT_OPENGL_ARB);
ADD_ATTRIB(WGL_DRAW_TO_WINDOW_ARB);
ADD_ATTRIB(WGL_PIXEL_TYPE_ARB);
ADD_ATTRIB(WGL_ACCELERATION_ARB);
ADD_ATTRIB(WGL_RED_BITS_ARB);
ADD_ATTRIB(WGL_RED_SHIFT_ARB);
ADD_ATTRIB(WGL_GREEN_BITS_ARB);
ADD_ATTRIB(WGL_GREEN_SHIFT_ARB);
ADD_ATTRIB(WGL_BLUE_BITS_ARB);
ADD_ATTRIB(WGL_BLUE_SHIFT_ARB);
ADD_ATTRIB(WGL_ALPHA_BITS_ARB);
ADD_ATTRIB(WGL_ALPHA_SHIFT_ARB);
ADD_ATTRIB(WGL_DEPTH_BITS_ARB);
ADD_ATTRIB(WGL_STENCIL_BITS_ARB);
ADD_ATTRIB(WGL_ACCUM_BITS_ARB);
ADD_ATTRIB(WGL_ACCUM_RED_BITS_ARB);
ADD_ATTRIB(WGL_ACCUM_GREEN_BITS_ARB);
ADD_ATTRIB(WGL_ACCUM_BLUE_BITS_ARB);
ADD_ATTRIB(WGL_ACCUM_ALPHA_BITS_ARB);
ADD_ATTRIB(WGL_AUX_BUFFERS_ARB);
ADD_ATTRIB(WGL_STEREO_ARB);
ADD_ATTRIB(WGL_DOUBLE_BUFFER_ARB);
if (_glfw.wgl.ARB_multisample)
addAttrib(WGL_SAMPLES_ARB);
ADD_ATTRIB(WGL_SAMPLES_ARB);
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (_glfw.wgl.ARB_framebuffer_sRGB || _glfw.wgl.EXT_framebuffer_sRGB)
addAttrib(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
ADD_ATTRIB(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB);
}
else
{
if (_glfw.wgl.EXT_colorspace)
addAttrib(WGL_COLORSPACE_EXT);
ADD_ATTRIB(WGL_COLORSPACE_EXT);
}
}
else
{
nativeCount = DescribePixelFormat(window->context.wgl.dc,
1,
sizeof(PIXELFORMATDESCRIPTOR),
NULL);
}
usableConfigs = _glfw_calloc(nativeCount, sizeof(_GLFWfbconfig));
@ -152,48 +142,48 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
return 0;
}
if (!findAttribValue(WGL_SUPPORT_OPENGL_ARB) ||
!findAttribValue(WGL_DRAW_TO_WINDOW_ARB))
if (!FIND_ATTRIB_VALUE(WGL_SUPPORT_OPENGL_ARB) ||
!FIND_ATTRIB_VALUE(WGL_DRAW_TO_WINDOW_ARB))
{
continue;
}
if (findAttribValue(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB)
if (FIND_ATTRIB_VALUE(WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB)
continue;
if (findAttribValue(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB)
if (FIND_ATTRIB_VALUE(WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB)
continue;
if (findAttribValue(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer)
if (FIND_ATTRIB_VALUE(WGL_DOUBLE_BUFFER_ARB) != fbconfig->doublebuffer)
continue;
u->redBits = findAttribValue(WGL_RED_BITS_ARB);
u->greenBits = findAttribValue(WGL_GREEN_BITS_ARB);
u->blueBits = findAttribValue(WGL_BLUE_BITS_ARB);
u->alphaBits = findAttribValue(WGL_ALPHA_BITS_ARB);
u->redBits = FIND_ATTRIB_VALUE(WGL_RED_BITS_ARB);
u->greenBits = FIND_ATTRIB_VALUE(WGL_GREEN_BITS_ARB);
u->blueBits = FIND_ATTRIB_VALUE(WGL_BLUE_BITS_ARB);
u->alphaBits = FIND_ATTRIB_VALUE(WGL_ALPHA_BITS_ARB);
u->depthBits = findAttribValue(WGL_DEPTH_BITS_ARB);
u->stencilBits = findAttribValue(WGL_STENCIL_BITS_ARB);
u->depthBits = FIND_ATTRIB_VALUE(WGL_DEPTH_BITS_ARB);
u->stencilBits = FIND_ATTRIB_VALUE(WGL_STENCIL_BITS_ARB);
u->accumRedBits = findAttribValue(WGL_ACCUM_RED_BITS_ARB);
u->accumGreenBits = findAttribValue(WGL_ACCUM_GREEN_BITS_ARB);
u->accumBlueBits = findAttribValue(WGL_ACCUM_BLUE_BITS_ARB);
u->accumAlphaBits = findAttribValue(WGL_ACCUM_ALPHA_BITS_ARB);
u->accumRedBits = FIND_ATTRIB_VALUE(WGL_ACCUM_RED_BITS_ARB);
u->accumGreenBits = FIND_ATTRIB_VALUE(WGL_ACCUM_GREEN_BITS_ARB);
u->accumBlueBits = FIND_ATTRIB_VALUE(WGL_ACCUM_BLUE_BITS_ARB);
u->accumAlphaBits = FIND_ATTRIB_VALUE(WGL_ACCUM_ALPHA_BITS_ARB);
u->auxBuffers = findAttribValue(WGL_AUX_BUFFERS_ARB);
u->auxBuffers = FIND_ATTRIB_VALUE(WGL_AUX_BUFFERS_ARB);
if (findAttribValue(WGL_STEREO_ARB))
if (FIND_ATTRIB_VALUE(WGL_STEREO_ARB))
u->stereo = GLFW_TRUE;
if (_glfw.wgl.ARB_multisample)
u->samples = findAttribValue(WGL_SAMPLES_ARB);
u->samples = FIND_ATTRIB_VALUE(WGL_SAMPLES_ARB);
if (ctxconfig->client == GLFW_OPENGL_API)
{
if (_glfw.wgl.ARB_framebuffer_sRGB ||
_glfw.wgl.EXT_framebuffer_sRGB)
{
if (findAttribValue(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
if (FIND_ATTRIB_VALUE(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB))
u->sRGB = GLFW_TRUE;
}
}
@ -201,7 +191,7 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
{
if (_glfw.wgl.EXT_colorspace)
{
if (findAttribValue(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT)
if (FIND_ATTRIB_VALUE(WGL_COLORSPACE_EXT) == WGL_COLORSPACE_SRGB_EXT)
u->sRGB = GLFW_TRUE;
}
}
@ -290,8 +280,8 @@ static int choosePixelFormatWGL(_GLFWwindow* window,
return pixelFormat;
}
#undef addAttrib
#undef findAttribValue
#undef ADD_ATTRIB
#undef FIND_ATTRIB_VALUE
static void makeContextCurrentWGL(_GLFWwindow* window)
{
@ -523,7 +513,7 @@ void _glfwTerminateWGL(void)
_glfwPlatformFreeModule(_glfw.wgl.instance);
}
#define setAttrib(a, v) \
#define SET_ATTRIB(a, v) \
{ \
assert(((size_t) index + 1) < sizeof(attribs) / sizeof(attribs[0])); \
attribs[index++] = a; \
@ -631,13 +621,13 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
{
if (ctxconfig->robustness == GLFW_NO_RESET_NOTIFICATION)
{
setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
WGL_NO_RESET_NOTIFICATION_ARB);
SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
WGL_NO_RESET_NOTIFICATION_ARB);
}
else if (ctxconfig->robustness == GLFW_LOSE_CONTEXT_ON_RESET)
{
setAttrib(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
WGL_LOSE_CONTEXT_ON_RESET_ARB);
SET_ATTRIB(WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB,
WGL_LOSE_CONTEXT_ON_RESET_ARB);
}
flags |= WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB;
@ -650,13 +640,13 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
{
if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_NONE)
{
setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB);
}
else if (ctxconfig->release == GLFW_RELEASE_BEHAVIOR_FLUSH)
{
setAttrib(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
SET_ATTRIB(WGL_CONTEXT_RELEASE_BEHAVIOR_ARB,
WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB);
}
}
}
@ -664,7 +654,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
if (ctxconfig->noerror)
{
if (_glfw.wgl.ARB_create_context_no_error)
setAttrib(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
SET_ATTRIB(WGL_CONTEXT_OPENGL_NO_ERROR_ARB, GLFW_TRUE);
}
// NOTE: Only request an explicitly versioned context when necessary, as
@ -672,17 +662,17 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
// highest version supported by the driver
if (ctxconfig->major != 1 || ctxconfig->minor != 0)
{
setAttrib(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
setAttrib(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
SET_ATTRIB(WGL_CONTEXT_MAJOR_VERSION_ARB, ctxconfig->major);
SET_ATTRIB(WGL_CONTEXT_MINOR_VERSION_ARB, ctxconfig->minor);
}
if (flags)
setAttrib(WGL_CONTEXT_FLAGS_ARB, flags);
SET_ATTRIB(WGL_CONTEXT_FLAGS_ARB, flags);
if (mask)
setAttrib(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
SET_ATTRIB(WGL_CONTEXT_PROFILE_MASK_ARB, mask);
setAttrib(0, 0);
SET_ATTRIB(0, 0);
window->context.wgl.handle =
wglCreateContextAttribsARB(window->context.wgl.dc, share, attribs);
@ -765,7 +755,7 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
return GLFW_TRUE;
}
#undef setAttrib
#undef SET_ATTRIB
GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
{
@ -788,3 +778,5 @@ GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* handle)
return window->context.wgl.handle;
}
#endif // _GLFW_WIN32

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(_GLFW_WIN32)
#include <stdlib.h>
static const GUID _glfw_GUID_DEVINTERFACE_HID =
@ -71,6 +73,16 @@ BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved)
//
static GLFWbool loadLibraries(void)
{
if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
(const WCHAR*) &_glfw,
(HMODULE*) &_glfw.win32.instance))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to retrieve own module handle");
return GLFW_FALSE;
}
_glfw.win32.user32.instance = _glfwPlatformLoadModule("user32.dll");
if (!_glfw.win32.user32.instance)
{
@ -91,6 +103,8 @@ static GLFWbool loadLibraries(void)
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetDpiForWindow");
_glfw.win32.user32.AdjustWindowRectExForDpi_ = (PFN_AdjustWindowRectExForDpi)
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "AdjustWindowRectExForDpi");
_glfw.win32.user32.GetSystemMetricsForDpi_ = (PFN_GetSystemMetricsForDpi)
_glfwPlatformGetModuleSymbol(_glfw.win32.user32.instance, "GetSystemMetricsForDpi");
_glfw.win32.dinput8.instance = _glfwPlatformLoadModule("dinput8.dll");
if (_glfw.win32.dinput8.instance)
@ -251,7 +265,6 @@ static void createKeyTables(void)
_glfw.win32.keycodes[0x151] = GLFW_KEY_PAGE_DOWN;
_glfw.win32.keycodes[0x149] = GLFW_KEY_PAGE_UP;
_glfw.win32.keycodes[0x045] = GLFW_KEY_PAUSE;
_glfw.win32.keycodes[0x146] = GLFW_KEY_PAUSE;
_glfw.win32.keycodes[0x039] = GLFW_KEY_SPACE;
_glfw.win32.keycodes[0x00F] = GLFW_KEY_TAB;
_glfw.win32.keycodes[0x03A] = GLFW_KEY_CAPS_LOCK;
@ -320,20 +333,69 @@ static void createKeyTables(void)
}
}
// Window procedure for the hidden helper window
//
static LRESULT CALLBACK helperWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DISPLAYCHANGE:
_glfwPollMonitorsWin32();
break;
case WM_DEVICECHANGE:
{
if (!_glfw.joysticksInitialized)
break;
if (wParam == DBT_DEVICEARRIVAL)
{
DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
_glfwDetectJoystickConnectionWin32();
}
else if (wParam == DBT_DEVICEREMOVECOMPLETE)
{
DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
_glfwDetectJoystickDisconnectionWin32();
}
break;
}
}
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
}
// Creates a dummy window for behind-the-scenes work
//
static GLFWbool createHelperWindow(void)
{
MSG msg;
WNDCLASSEXW wc = { sizeof(wc) };
wc.style = CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) helperWindowProc;
wc.hInstance = _glfw.win32.instance;
wc.lpszClassName = L"GLFW3 Helper";
_glfw.win32.helperWindowClass = RegisterClassExW(&wc);
if (!_glfw.win32.helperWindowClass)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"WIn32: Failed to register helper window class");
return GLFW_FALSE;
}
_glfw.win32.helperWindowHandle =
CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
_GLFW_WNDCLASSNAME,
MAKEINTATOM(_glfw.win32.helperWindowClass),
L"GLFW message window",
WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0, 0, 1, 1,
NULL, NULL,
GetModuleHandleW(NULL),
_glfw.win32.instance,
NULL);
if (!_glfw.win32.helperWindowHandle)
@ -483,7 +545,7 @@ void _glfwUpdateKeyNamesWin32(void)
vk = vks[key - GLFW_KEY_KP_0];
}
else
vk = MapVirtualKey(scancode, MAPVK_VSC_TO_VK);
vk = MapVirtualKeyW(scancode, MAPVK_VSC_TO_VK);
length = ToUnicode(vk, scancode, state,
chars, sizeof(chars) / sizeof(WCHAR),
@ -491,6 +553,8 @@ void _glfwUpdateKeyNamesWin32(void)
if (length == -1)
{
// This is a dead key, so we need a second simulated key press
// to make it output its own character (usually a diacritic)
length = ToUnicode(vk, scancode, state,
chars, sizeof(chars) / sizeof(WCHAR),
0);
@ -506,7 +570,8 @@ void _glfwUpdateKeyNamesWin32(void)
}
}
// Replacement for IsWindowsVersionOrGreater as MinGW lacks versionhelpers.h
// Replacement for IsWindowsVersionOrGreater, as we cannot rely on the
// application having a correct embedded manifest
//
BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp)
{
@ -626,16 +691,13 @@ int _glfwInitWin32(void)
createKeyTables();
_glfwUpdateKeyNamesWin32();
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
if (_glfwIsWindows10Version1703OrGreaterWin32())
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
else if (IsWindows8Point1OrGreater())
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
else if (IsWindowsVistaOrGreater())
SetProcessDPIAware();
if (!_glfwRegisterWindowClassWin32())
return GLFW_FALSE;
if (!createHelperWindow())
return GLFW_FALSE;
@ -650,15 +712,20 @@ void _glfwTerminateWin32(void)
if (_glfw.win32.helperWindowHandle)
DestroyWindow(_glfw.win32.helperWindowHandle);
_glfwUnregisterWindowClassWin32();
if (_glfw.win32.helperWindowClass)
UnregisterClassW(MAKEINTATOM(_glfw.win32.helperWindowClass), _glfw.win32.instance);
if (_glfw.win32.mainWindowClass)
UnregisterClassW(MAKEINTATOM(_glfw.win32.mainWindowClass), _glfw.win32.instance);
_glfw_free(_glfw.win32.clipboardString);
_glfw_free(_glfw.win32.rawInput);
_glfwTerminateWGL();
_glfwTerminateEGL();
_glfwTerminateOSMesa();
freeLibraries();
}
#endif // _GLFW_WIN32

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(_GLFW_WIN32)
#include <stdio.h>
#include <math.h>
@ -256,6 +258,8 @@ static GLFWbool supportsXInput(const GUID* guid)
//
static void closeJoystick(_GLFWjoystick* js)
{
_glfwInputJoystick(js, GLFW_DISCONNECTED);
if (js->win32.device)
{
IDirectInputDevice8_Unacquire(js->win32.device);
@ -263,9 +267,7 @@ static void closeJoystick(_GLFWjoystick* js)
}
_glfw_free(js->win32.objects);
_glfwFreeJoystick(js);
_glfwInputJoystick(js, GLFW_DISCONNECTED);
}
// DirectInput device object enumeration callback
@ -357,7 +359,7 @@ static BOOL CALLBACK deviceCallback(const DIDEVICEINSTANCE* di, void* user)
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
js = _glfw.joysticks + jid;
if (js->present)
if (js->connected)
{
if (memcmp(&js->win32.guid, &di->guidInstance, sizeof(GUID)) == 0)
return DIENUM_CONTINUE;
@ -508,7 +510,7 @@ void _glfwDetectJoystickConnectionWin32(void)
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (_glfw.joysticks[jid].present &&
if (_glfw.joysticks[jid].connected &&
_glfw.joysticks[jid].win32.device == NULL &&
_glfw.joysticks[jid].win32.index == index)
{
@ -560,7 +562,7 @@ void _glfwDetectJoystickDisconnectionWin32(void)
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
_GLFWjoystick* js = _glfw.joysticks + jid;
if (js->present)
if (js->connected)
_glfwPollJoystickWin32(js, _GLFW_POLL_PRESENCE);
}
}
@ -574,7 +576,7 @@ GLFWbool _glfwInitJoysticksWin32(void)
{
if (_glfw.win32.dinput8.instance)
{
if (FAILED(DirectInput8Create(GetModuleHandle(NULL),
if (FAILED(DirectInput8Create(_glfw.win32.instance,
DIRECTINPUT_VERSION,
&IID_IDirectInput8W,
(void**) &_glfw.win32.dinput8.api,
@ -601,13 +603,13 @@ void _glfwTerminateJoysticksWin32(void)
IDirectInput8_Release(_glfw.win32.dinput8.api);
}
int _glfwPollJoystickWin32(_GLFWjoystick* js, int mode)
GLFWbool _glfwPollJoystickWin32(_GLFWjoystick* js, int mode)
{
if (js->win32.device)
{
int i, ai = 0, bi = 0, pi = 0;
HRESULT result;
DIJOYSTATE state;
DIJOYSTATE state = {0};
IDirectInputDevice8_Poll(js->win32.device);
result = IDirectInputDevice8_GetDeviceState(js->win32.device,
@ -756,3 +758,5 @@ void _glfwUpdateGamepadGUIDWin32(char* guid)
}
}
#endif // _GLFW_WIN32

View File

@ -27,8 +27,6 @@
#define GLFW_WIN32_JOYSTICK_STATE _GLFWjoystickWin32 win32;
#define GLFW_WIN32_LIBRARY_JOYSTICK_STATE
#define GLFW_BUILD_WIN32_MAPPINGS
// Joystick element (axis, button or slider)
//
typedef struct _GLFWjoyobjectWin32

View File

@ -28,6 +28,8 @@
#include "internal.h"
#if defined(GLFW_BUILD_WIN32_MODULE)
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
@ -47,3 +49,5 @@ GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name)
return (GLFWproc) GetProcAddress((HMODULE) module, name);
}
#endif // GLFW_BUILD_WIN32_MODULE

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(_GLFW_WIN32)
#include <stdlib.h>
#include <string.h>
#include <limits.h>
@ -381,7 +383,7 @@ void _glfwGetMonitorWorkareaWin32(_GLFWmonitor* monitor,
int* width, int* height)
{
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfo(monitor->win32.handle, &mi);
GetMonitorInfoW(monitor->win32.handle, &mi);
if (xpos)
*xpos = mi.rcWork.left;
@ -545,3 +547,5 @@ GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* handle)
return monitor->win32.publicDisplayName;
}
#endif // _GLFW_WIN32

View File

@ -162,7 +162,9 @@ typedef enum
#define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ((HANDLE) -4)
#endif /*DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2*/
// HACK: Define versionhelpers.h functions manually as MinGW lacks the header
// Replacement for versionhelpers.h macros, as we cannot rely on the
// application having a correct embedded manifest
//
#define IsWindowsVistaOrGreater() \
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_VISTA), \
LOBYTE(_WIN32_WINNT_VISTA), 0)
@ -176,9 +178,11 @@ typedef enum
_glfwIsWindowsVersionOrGreaterWin32(HIBYTE(_WIN32_WINNT_WINBLUE), \
LOBYTE(_WIN32_WINNT_WINBLUE), 0)
#define _glfwIsWindows10AnniversaryUpdateOrGreaterWin32() \
// Windows 10 Anniversary Update
#define _glfwIsWindows10Version1607OrGreaterWin32() \
_glfwIsWindows10BuildOrGreaterWin32(14393)
#define _glfwIsWindows10CreatorsUpdateOrGreaterWin32() \
// Windows 10 Creators Update
#define _glfwIsWindows10Version1703OrGreaterWin32() \
_glfwIsWindows10BuildOrGreaterWin32(15063)
// HACK: Define macros that some xinput.h variants don't
@ -283,12 +287,14 @@ typedef BOOL (WINAPI * PFN_EnableNonClientDpiScaling)(HWND);
typedef BOOL (WINAPI * PFN_SetProcessDpiAwarenessContext)(HANDLE);
typedef UINT (WINAPI * PFN_GetDpiForWindow)(HWND);
typedef BOOL (WINAPI * PFN_AdjustWindowRectExForDpi)(LPRECT,DWORD,BOOL,DWORD,UINT);
typedef int (WINAPI * PFN_GetSystemMetricsForDpi)(int,UINT);
#define SetProcessDPIAware _glfw.win32.user32.SetProcessDPIAware_
#define ChangeWindowMessageFilterEx _glfw.win32.user32.ChangeWindowMessageFilterEx_
#define EnableNonClientDpiScaling _glfw.win32.user32.EnableNonClientDpiScaling_
#define SetProcessDpiAwarenessContext _glfw.win32.user32.SetProcessDpiAwarenessContext_
#define GetDpiForWindow _glfw.win32.user32.GetDpiForWindow_
#define AdjustWindowRectExForDpi _glfw.win32.user32.AdjustWindowRectExForDpi_
#define GetSystemMetricsForDpi _glfw.win32.user32.GetSystemMetricsForDpi_
// dwmapi.dll function pointer typedefs
typedef HRESULT (WINAPI * PFN_DwmIsCompositionEnabled)(BOOL*);
@ -352,10 +358,6 @@ typedef struct VkWin32SurfaceCreateInfoKHR
typedef VkResult (APIENTRY *PFN_vkCreateWin32SurfaceKHR)(VkInstance,const VkWin32SurfaceCreateInfoKHR*,const VkAllocationCallbacks*,VkSurfaceKHR*);
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR)(VkPhysicalDevice,uint32_t);
#if !defined(_GLFW_WNDCLASSNAME)
#define _GLFW_WNDCLASSNAME L"GLFW30"
#endif
#define GLFW_WIN32_WINDOW_STATE _GLFWwindowWin32 win32;
#define GLFW_WIN32_LIBRARY_WINDOW_STATE _GLFWlibraryWin32 win32;
#define GLFW_WIN32_MONITOR_STATE _GLFWmonitorWin32 win32;
@ -436,7 +438,10 @@ typedef struct _GLFWwindowWin32
//
typedef struct _GLFWlibraryWin32
{
HINSTANCE instance;
HWND helperWindowHandle;
ATOM helperWindowClass;
ATOM mainWindowClass;
HDEVNOTIFY deviceNotificationHandle;
int acquiredMonitorCount;
char* clipboardString;
@ -447,6 +452,8 @@ typedef struct _GLFWlibraryWin32
double restoreCursorPosX, restoreCursorPosY;
// The window whose disabled cursor mode is active
_GLFWwindow* disabledCursorWindow;
// The window the cursor is captured in
_GLFWwindow* capturedCursorWindow;
RAWINPUT* rawInput;
int rawInputSize;
UINT mouseTrailSize;
@ -471,6 +478,7 @@ typedef struct _GLFWlibraryWin32
PFN_SetProcessDpiAwarenessContext SetProcessDpiAwarenessContext_;
PFN_GetDpiForWindow GetDpiForWindow_;
PFN_AdjustWindowRectExForDpi AdjustWindowRectExForDpi_;
PFN_GetSystemMetricsForDpi GetSystemMetricsForDpi_;
} user32;
struct {
@ -519,9 +527,6 @@ GLFWbool _glfwConnectWin32(int platformID, _GLFWplatform* platform);
int _glfwInitWin32(void);
void _glfwTerminateWin32(void);
GLFWbool _glfwRegisterWindowClassWin32(void);
void _glfwUnregisterWindowClassWin32(void);
WCHAR* _glfwCreateWideStringFromUTF8Win32(const char* source);
char* _glfwCreateUTF8FromWideStringWin32(const WCHAR* source);
BOOL _glfwIsWindowsVersionOrGreaterWin32(WORD major, WORD minor, WORD sp);
@ -534,7 +539,7 @@ void _glfwSetVideoModeWin32(_GLFWmonitor* monitor, const GLFWvidmode* desired);
void _glfwRestoreVideoModeWin32(_GLFWmonitor* monitor);
void _glfwGetHMONITORContentScaleWin32(HMONITOR handle, float* xscale, float* yscale);
int _glfwCreateWindowWin32(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
GLFWbool _glfwCreateWindowWin32(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
void _glfwDestroyWindowWin32(_GLFWwindow* window);
void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title);
void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images);
@ -555,12 +560,12 @@ void _glfwHideWindowWin32(_GLFWwindow* window);
void _glfwRequestWindowAttentionWin32(_GLFWwindow* window);
void _glfwFocusWindowWin32(_GLFWwindow* window);
void _glfwSetWindowMonitorWin32(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate);
int _glfwWindowFocusedWin32(_GLFWwindow* window);
int _glfwWindowIconifiedWin32(_GLFWwindow* window);
int _glfwWindowVisibleWin32(_GLFWwindow* window);
int _glfwWindowMaximizedWin32(_GLFWwindow* window);
int _glfwWindowHoveredWin32(_GLFWwindow* window);
int _glfwFramebufferTransparentWin32(_GLFWwindow* window);
GLFWbool _glfwWindowFocusedWin32(_GLFWwindow* window);
GLFWbool _glfwWindowIconifiedWin32(_GLFWwindow* window);
GLFWbool _glfwWindowVisibleWin32(_GLFWwindow* window);
GLFWbool _glfwWindowMaximizedWin32(_GLFWwindow* window);
GLFWbool _glfwWindowHoveredWin32(_GLFWwindow* window);
GLFWbool _glfwFramebufferTransparentWin32(_GLFWwindow* window);
void _glfwSetWindowResizableWin32(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowDecoratedWin32(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowFloatingWin32(_GLFWwindow* window, GLFWbool enabled);
@ -581,8 +586,8 @@ void _glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos);
void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode);
const char* _glfwGetScancodeNameWin32(int scancode);
int _glfwGetKeyScancodeWin32(int key);
int _glfwCreateCursorWin32(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
int _glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape);
GLFWbool _glfwCreateCursorWin32(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
GLFWbool _glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape);
void _glfwDestroyCursorWin32(_GLFWcursor* cursor);
void _glfwSetCursorWin32(_GLFWwindow* window, _GLFWcursor* cursor);
void _glfwSetClipboardStringWin32(const char* string);
@ -593,7 +598,7 @@ EGLNativeDisplayType _glfwGetEGLNativeDisplayWin32(void);
EGLNativeWindowType _glfwGetEGLNativeWindowWin32(_GLFWwindow* window);
void _glfwGetRequiredInstanceExtensionsWin32(char** extensions);
int _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
GLFWbool _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
void _glfwFreeMonitorWin32(_GLFWmonitor* monitor);
@ -607,7 +612,7 @@ void _glfwSetGammaRampWin32(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
GLFWbool _glfwInitJoysticksWin32(void);
void _glfwTerminateJoysticksWin32(void);
int _glfwPollJoystickWin32(_GLFWjoystick* js, int mode);
GLFWbool _glfwPollJoystickWin32(_GLFWjoystick* js, int mode);
const char* _glfwGetMappingNameWin32(void);
void _glfwUpdateGamepadGUIDWin32(char* guid);

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(GLFW_BUILD_WIN32_THREAD)
#include <assert.h>
@ -96,3 +98,5 @@ void _glfwPlatformUnlockMutex(_GLFWmutex* mutex)
LeaveCriticalSection(&mutex->win32.section);
}
#endif // GLFW_BUILD_WIN32_THREAD

View File

@ -29,6 +29,7 @@
#include "internal.h"
#if defined(GLFW_BUILD_WIN32_TIMER)
//////////////////////////////////////////////////////////////////////////
////// GLFW platform API //////
@ -51,3 +52,5 @@ uint64_t _glfwPlatformGetTimerFrequency(void)
return _glfw.timer.win32.frequency;
}
#endif // GLFW_BUILD_WIN32_TIMER

View File

@ -28,8 +28,11 @@
//========================================================================
#include "internal.h"
#include "glfw3ext_internal.h" // x-studio spec
#if defined(_GLFW_WIN32)
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@ -104,8 +107,7 @@ static const GLFWimage* chooseImage(int count, const GLFWimage* images,
// Creates an RGBA icon or cursor
//
static HICON createIcon(const GLFWimage* image,
int xhot, int yhot, GLFWbool icon)
static HICON createIcon(const GLFWimage* image, int xhot, int yhot, GLFWbool icon)
{
int i;
HDC dc;
@ -192,53 +194,38 @@ static HICON createIcon(const GLFWimage* image,
return handle;
}
// Translate content area size to full window size according to styles and DPI
//
static void getFullWindowSize(DWORD style, DWORD exStyle,
int contentWidth, int contentHeight,
int* fullWidth, int* fullHeight,
UINT dpi)
{
RECT rect = { 0, 0, contentWidth, contentHeight };
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
else
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
*fullWidth = rect.right - rect.left;
*fullHeight = rect.bottom - rect.top;
}
// Enforce the content area aspect ratio based on which edge is being dragged
//
static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
{
int xoff, yoff;
UINT dpi = USER_DEFAULT_SCREEN_DPI;
RECT frame = {0};
const float ratio = (float) window->numer / (float) window->denom;
const DWORD style = getWindowStyle(window);
const DWORD exStyle = getWindowExStyle(window);
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
dpi = GetDpiForWindow(window->win32.handle);
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
0, 0, &xoff, &yoff, dpi);
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
AdjustWindowRectExForDpi(&frame, style, FALSE, exStyle,
GetDpiForWindow(window->win32.handle));
}
else
AdjustWindowRectEx(&frame, style, FALSE, exStyle);
if (edge == WMSZ_LEFT || edge == WMSZ_BOTTOMLEFT ||
edge == WMSZ_RIGHT || edge == WMSZ_BOTTOMRIGHT)
{
area->bottom = area->top + yoff +
(int) ((area->right - area->left - xoff) / ratio);
area->bottom = area->top + (frame.bottom - frame.top) +
(int) (((area->right - area->left) - (frame.right - frame.left)) / ratio);
}
else if (edge == WMSZ_TOPLEFT || edge == WMSZ_TOPRIGHT)
{
area->top = area->bottom - yoff -
(int) ((area->right - area->left - xoff) / ratio);
area->top = area->bottom - (frame.bottom - frame.top) -
(int) (((area->right - area->left) - (frame.right - frame.left)) / ratio);
}
else if (edge == WMSZ_TOP || edge == WMSZ_BOTTOM)
{
area->right = area->left + xoff +
(int) ((area->bottom - area->top - yoff) * ratio);
area->right = area->left + (frame.right - frame.left) +
(int) (((area->bottom - area->top) - (frame.bottom - frame.top)) * ratio);
}
}
@ -246,7 +233,8 @@ static void applyAspectRatio(_GLFWwindow* window, int edge, RECT* area)
//
static void updateCursorImage(_GLFWwindow* window)
{
if (window->cursorMode == GLFW_CURSOR_NORMAL)
if (window->cursorMode == GLFW_CURSOR_NORMAL ||
window->cursorMode == GLFW_CURSOR_CAPTURED)
{
if (window->cursor)
SetCursor(window->cursor->win32.handle);
@ -257,20 +245,24 @@ static void updateCursorImage(_GLFWwindow* window)
SetCursor(NULL);
}
// Updates the cursor clip rect
// Sets the cursor clip rect to the window content area
//
static void updateClipRect(_GLFWwindow* window)
static void captureCursor(_GLFWwindow* window)
{
if (window)
{
RECT clipRect;
GetClientRect(window->win32.handle, &clipRect);
ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);
ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);
ClipCursor(&clipRect);
}
else
ClipCursor(NULL);
RECT clipRect;
GetClientRect(window->win32.handle, &clipRect);
ClientToScreen(window->win32.handle, (POINT*) &clipRect.left);
ClientToScreen(window->win32.handle, (POINT*) &clipRect.right);
ClipCursor(&clipRect);
_glfw.win32.capturedCursorWindow = window;
}
// Disabled clip cursor
//
static void releaseCursor(void)
{
ClipCursor(NULL);
_glfw.win32.capturedCursorWindow = NULL;
}
// Enables WM_INPUT messages for the mouse for the specified window
@ -309,7 +301,7 @@ static void disableCursor(_GLFWwindow* window)
&_glfw.win32.restoreCursorPosY);
updateCursorImage(window);
_glfwCenterCursorInContentArea(window);
updateClipRect(window);
captureCursor(window);
if (window->rawMouseMotion)
enableRawMouseMotion(window);
@ -323,7 +315,7 @@ static void enableCursor(_GLFWwindow* window)
disableRawMouseMotion(window);
_glfw.win32.disabledCursorWindow = NULL;
updateClipRect(NULL);
releaseCursor();
_glfwSetCursorPosWin32(window,
_glfw.win32.restoreCursorPosX,
_glfw.win32.restoreCursorPosY);
@ -361,7 +353,7 @@ static void updateWindowStyles(const _GLFWwindow* window)
GetClientRect(window->win32.handle, &rect);
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, style, FALSE,
getWindowExStyle(window),
@ -441,7 +433,7 @@ static int getKeyMods(void)
static void fitToMonitor(_GLFWwindow* window)
{
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfo(window->monitor->win32.handle, &mi);
GetMonitorInfoW(window->monitor->win32.handle, &mi);
SetWindowPos(window->win32.handle, HWND_TOPMOST,
mi.rcMonitor.left,
mi.rcMonitor.top,
@ -460,8 +452,8 @@ static void acquireMonitor(_GLFWwindow* window)
// HACK: When mouse trails are enabled the cursor becomes invisible when
// the OpenGL ICD switches to page flipping
SystemParametersInfo(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
SystemParametersInfo(SPI_SETMOUSETRAILS, 0, 0, 0);
SystemParametersInfoW(SPI_GETMOUSETRAILS, 0, &_glfw.win32.mouseTrailSize, 0);
SystemParametersInfoW(SPI_SETMOUSETRAILS, 0, 0, 0);
}
if (!window->monitor->window)
@ -484,67 +476,83 @@ static void releaseMonitor(_GLFWwindow* window)
SetThreadExecutionState(ES_CONTINUOUS);
// HACK: Restore mouse trail length saved in acquireMonitor
SystemParametersInfo(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);
SystemParametersInfoW(SPI_SETMOUSETRAILS, _glfw.win32.mouseTrailSize, 0, 0);
}
_glfwInputMonitorWindow(window->monitor, NULL);
_glfwRestoreVideoModeWin32(window->monitor);
}
// Window callback function (handles window messages)
// Manually maximize the window, for when SW_MAXIMIZE cannot be used
//
static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
static void maximizeWindowManually(_GLFWwindow* window)
{
RECT rect;
DWORD style;
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfoW(MonitorFromWindow(window->win32.handle,
MONITOR_DEFAULTTONEAREST), &mi);
rect = mi.rcWork;
if (window->maxwidth != GLFW_DONT_CARE && window->maxheight != GLFW_DONT_CARE)
{
rect.right = _glfw_min(rect.right, rect.left + window->maxwidth);
rect.bottom = _glfw_min(rect.bottom, rect.top + window->maxheight);
}
style = GetWindowLongW(window->win32.handle, GWL_STYLE);
style |= WS_MAXIMIZE;
SetWindowLongW(window->win32.handle, GWL_STYLE, style);
if (window->decorated)
{
const DWORD exStyle = GetWindowLongW(window->win32.handle, GWL_EXSTYLE);
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
const UINT dpi = GetDpiForWindow(window->win32.handle);
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle, dpi);
OffsetRect(&rect, 0, GetSystemMetricsForDpi(SM_CYCAPTION, dpi));
}
else
{
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
OffsetRect(&rect, 0, GetSystemMetrics(SM_CYCAPTION));
}
rect.bottom = _glfw_min(rect.bottom, mi.rcWork.bottom);
}
SetWindowPos(window->win32.handle, HWND_TOP,
rect.left,
rect.top,
rect.right - rect.left,
rect.bottom - rect.top,
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
}
// Window procedure for user-created windows
//
static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
_GLFWwindow* window = GetPropW(hWnd, L"GLFW");
if (!window)
{
// This is the message handling for the hidden helper window
// and for a regular window during its initial creation
switch (uMsg)
if (uMsg == WM_NCCREATE)
{
case WM_NCCREATE:
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
{
const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam;
const _GLFWwndconfig* wndconfig = cs->lpCreateParams;
const CREATESTRUCTW* cs = (const CREATESTRUCTW*) lParam;
const _GLFWwndconfig* wndconfig = cs->lpCreateParams;
// On per-monitor DPI aware V1 systems, only enable
// non-client scaling for windows that scale the client area
// We need WM_GETDPISCALEDSIZE from V2 to keep the client
// area static when the non-client area is scaled
if (wndconfig && wndconfig->scaleToMonitor)
EnableNonClientDpiScaling(hWnd);
}
break;
}
case WM_DISPLAYCHANGE:
_glfwPollMonitorsWin32();
break;
case WM_DEVICECHANGE:
{
if (!_glfw.joysticksInitialized)
break;
if (wParam == DBT_DEVICEARRIVAL)
{
DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
_glfwDetectJoystickConnectionWin32();
}
else if (wParam == DBT_DEVICEREMOVECOMPLETE)
{
DEV_BROADCAST_HDR* dbh = (DEV_BROADCAST_HDR*) lParam;
if (dbh && dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
_glfwDetectJoystickDisconnectionWin32();
}
break;
// On per-monitor DPI aware V1 systems, only enable
// non-client scaling for windows that scale the client area
// We need WM_GETDPISCALEDSIZE from V2 to keep the client
// area static when the non-client area is scaled
if (wndconfig && wndconfig->scaleToMonitor)
EnableNonClientDpiScaling(hWnd);
}
}
@ -574,6 +582,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
{
if (window->cursorMode == GLFW_CURSOR_DISABLED)
disableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
window->win32.frameAction = GLFW_FALSE;
}
@ -592,6 +602,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
if (window->cursorMode == GLFW_CURSOR_DISABLED)
disableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
return 0;
}
@ -600,6 +612,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
{
if (window->cursorMode == GLFW_CURSOR_DISABLED)
enableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
releaseCursor();
if (window->monitor && window->autoIconify)
_glfwIconifyWindowWin32(window);
@ -711,6 +725,18 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
scancode = MapVirtualKeyW((UINT) wParam, MAPVK_VK_TO_VSC);
}
// HACK: Alt+PrtSc has a different scancode than just PrtSc
if (scancode == 0x54)
scancode = 0x137;
// HACK: Ctrl+Pause has a different scancode than just Pause
if (scancode == 0x146)
scancode = 0x45;
// HACK: CJK IME sets the extended bit for right Shift
if (scancode == 0x136)
scancode = 0x36;
key = _glfw.win32.keycodes[scancode];
// The Ctrl keys require special handling
@ -962,6 +988,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
// resizing the window or using the window menu
if (window->cursorMode == GLFW_CURSOR_DISABLED)
enableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
releaseCursor();
break;
}
@ -976,6 +1004,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
// resizing the window or using the menu
if (window->cursorMode == GLFW_CURSOR_DISABLED)
disableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
break;
}
@ -989,8 +1019,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
(window->win32.maximized &&
wParam != SIZE_RESTORED);
if (_glfw.win32.disabledCursorWindow == window)
updateClipRect(window);
if (_glfw.win32.capturedCursorWindow == window)
captureCursor(window);
if (window->win32.iconified != iconified)
_glfwInputWindowIconify(window, iconified);
@ -1025,8 +1055,8 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_MOVE:
{
if (_glfw.win32.disabledCursorWindow == window)
updateClipRect(window);
if (_glfw.win32.capturedCursorWindow == window)
captureCursor(window);
// NOTE: This cannot use LOWORD/HIWORD recommended by MSDN, as
// those macros do not handle negative window positions correctly
@ -1050,31 +1080,34 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
case WM_GETMINMAXINFO:
{
int xoff, yoff;
UINT dpi = USER_DEFAULT_SCREEN_DPI;
RECT frame = {0};
MINMAXINFO* mmi = (MINMAXINFO*) lParam;
const DWORD style = getWindowStyle(window);
const DWORD exStyle = getWindowExStyle(window);
if (window->monitor)
break;
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
dpi = GetDpiForWindow(window->win32.handle);
getFullWindowSize(getWindowStyle(window), getWindowExStyle(window),
0, 0, &xoff, &yoff, dpi);
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
AdjustWindowRectExForDpi(&frame, style, FALSE, exStyle,
GetDpiForWindow(window->win32.handle));
}
else
AdjustWindowRectEx(&frame, style, FALSE, exStyle);
if (window->minwidth != GLFW_DONT_CARE &&
window->minheight != GLFW_DONT_CARE)
{
mmi->ptMinTrackSize.x = window->minwidth + xoff;
mmi->ptMinTrackSize.y = window->minheight + yoff;
mmi->ptMinTrackSize.x = window->minwidth + frame.right - frame.left;
mmi->ptMinTrackSize.y = window->minheight + frame.bottom - frame.top;
}
if (window->maxwidth != GLFW_DONT_CARE &&
window->maxheight != GLFW_DONT_CARE)
{
mmi->ptMaxTrackSize.x = window->maxwidth + xoff;
mmi->ptMaxTrackSize.y = window->maxheight + yoff;
mmi->ptMaxTrackSize.x = window->maxwidth + frame.right - frame.left;
mmi->ptMaxTrackSize.y = window->maxheight + frame.bottom - frame.top;
}
if (!window->decorated)
@ -1085,7 +1118,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
ZeroMemory(&mi, sizeof(mi));
mi.cbSize = sizeof(mi);
GetMonitorInfo(mh, &mi);
GetMonitorInfoW(mh, &mi);
mmi->ptMaxPosition.x = mi.rcWork.left - mi.rcMonitor.left;
mmi->ptMaxPosition.y = mi.rcWork.top - mi.rcMonitor.top;
@ -1132,7 +1165,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
break;
// Adjust the window size to keep the content area size constant
if (_glfwIsWindows10CreatorsUpdateOrGreaterWin32())
if (_glfwIsWindows10Version1703OrGreaterWin32())
{
RECT source = {0}, target = {0};
SIZE* size = (SIZE*) lParam;
@ -1163,7 +1196,7 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
// need it to compensate for non-client area scaling
if (!window->monitor &&
(window->win32.scaleToMonitor ||
_glfwIsWindows10CreatorsUpdateOrGreaterWin32()))
_glfwIsWindows10Version1703OrGreaterWin32()))
{
RECT* suggested = (RECT*) lParam;
SetWindowPos(window->win32.handle, HWND_TOP,
@ -1233,36 +1266,80 @@ static int createNativeWindow(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWfbconfig* fbconfig)
{
int xpos, ypos, fullWidth, fullHeight;
int frameX, frameY, frameWidth, frameHeight;
WCHAR* wideTitle;
DWORD style = getWindowStyle(window);
DWORD exStyle = getWindowExStyle(window);
if (!_glfw.win32.mainWindowClass)
{
WNDCLASSEXW wc = { sizeof(wc) };
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = windowProc;
wc.hInstance = _glfw.win32.instance;
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
#if defined(_GLFW_WNDCLASSNAME)
wc.lpszClassName = _GLFW_WNDCLASSNAME;
#else
wc.lpszClassName = L"GLFW30";
#endif
// Load user-provided icon if available
wc.hIcon = LoadImageW(GetModuleHandleW(NULL),
L"GLFW_ICON", IMAGE_ICON,
0, 0, LR_DEFAULTSIZE | LR_SHARED);
if (!wc.hIcon)
{
// No user-provided icon found, load default icon
wc.hIcon = LoadImageW(NULL,
IDI_APPLICATION, IMAGE_ICON,
0, 0, LR_DEFAULTSIZE | LR_SHARED);
}
_glfw.win32.mainWindowClass = RegisterClassExW(&wc);
if (!_glfw.win32.mainWindowClass)
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to register window class");
return GLFW_FALSE;
}
}
if (window->monitor)
{
GLFWvidmode mode;
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfoW(window->monitor->win32.handle, &mi);
// NOTE: This window placement is temporary and approximate, as the
// correct position and size cannot be known until the monitor
// video mode has been picked in _glfwSetVideoModeWin32
_glfwGetMonitorPosWin32(window->monitor, &xpos, &ypos);
_glfwGetVideoModeWin32(window->monitor, &mode);
fullWidth = mode.width;
fullHeight = mode.height;
frameX = mi.rcMonitor.left;
frameY = mi.rcMonitor.top;
frameWidth = mi.rcMonitor.right - mi.rcMonitor.left;
frameHeight = mi.rcMonitor.bottom - mi.rcMonitor.top;
}
else
{
xpos = CW_USEDEFAULT;
ypos = CW_USEDEFAULT;
RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
window->win32.maximized = wndconfig->maximized;
if (wndconfig->maximized)
style |= WS_MAXIMIZE;
getFullWindowSize(style, exStyle,
wndconfig->width, wndconfig->height,
&fullWidth, &fullHeight,
USER_DEFAULT_SCREEN_DPI);
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
if (wndconfig->xpos == GLFW_ANY_POSITION && wndconfig->ypos == GLFW_ANY_POSITION)
{
frameX = CW_USEDEFAULT;
frameY = CW_USEDEFAULT;
}
else
{
frameX = wndconfig->xpos + rect.left;
frameY = wndconfig->ypos + rect.top;
}
frameWidth = rect.right - rect.left;
frameHeight = rect.bottom - rect.top;
}
wideTitle = _glfwCreateWideStringFromUTF8Win32(wndconfig->title);
@ -1270,14 +1347,14 @@ static int createNativeWindow(_GLFWwindow* window,
return GLFW_FALSE;
window->win32.handle = CreateWindowExW(exStyle,
_GLFW_WNDCLASSNAME,
MAKEINTATOM(_glfw.win32.mainWindowClass),
wideTitle,
style,
xpos, ypos,
fullWidth, fullHeight,
frameX, frameY,
frameWidth, frameHeight,
_glfwx.hwndGLParent, // x-studio spec, create as child window support.
NULL, // No window menu
GetModuleHandleW(NULL),
_glfw.win32.instance,
(LPVOID) wndconfig);
_glfw_free(wideTitle);
@ -1304,18 +1381,22 @@ static int createNativeWindow(_GLFWwindow* window,
window->win32.scaleToMonitor = wndconfig->scaleToMonitor;
window->win32.keymenu = wndconfig->win32.keymenu;
// Adjust window rect to account for DPI scaling of the window frame and
// (if enabled) DPI scaling of the content area
// This cannot be done until we know what monitor the window was placed on
if (!window->monitor)
{
RECT rect = { 0, 0, wndconfig->width, wndconfig->height };
WINDOWPLACEMENT wp = { sizeof(wp) };
const HMONITOR mh = MonitorFromWindow(window->win32.handle,
MONITOR_DEFAULTTONEAREST);
// Adjust window rect to account for DPI scaling of the window frame and
// (if enabled) DPI scaling of the content area
// This cannot be done until we know what monitor the window was placed on
// Only update the restored window rect as the window may be maximized
if (wndconfig->scaleToMonitor)
{
float xscale, yscale;
_glfwGetWindowContentScaleWin32(window, &xscale, &yscale);
_glfwGetHMONITORContentScaleWin32(mh, &xscale, &yscale);
if (xscale > 0.f && yscale > 0.f)
{
@ -1324,10 +1405,7 @@ static int createNativeWindow(_GLFWwindow* window,
}
}
ClientToScreen(window->win32.handle, (POINT*) &rect.left);
ClientToScreen(window->win32.handle, (POINT*) &rect.right);
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, style, FALSE, exStyle,
GetDpiForWindow(window->win32.handle));
@ -1335,11 +1413,30 @@ static int createNativeWindow(_GLFWwindow* window,
else
AdjustWindowRectEx(&rect, style, FALSE, exStyle);
// Only update the restored window rect as the window may be maximized
GetWindowPlacement(window->win32.handle, &wp);
OffsetRect(&rect,
wp.rcNormalPosition.left - rect.left,
wp.rcNormalPosition.top - rect.top);
wp.rcNormalPosition = rect;
wp.showCmd = SW_HIDE;
SetWindowPlacement(window->win32.handle, &wp);
// Adjust rect of maximized undecorated window, because by default Windows will
// make such a window cover the whole monitor instead of its workarea
if (wndconfig->maximized && !wndconfig->decorated)
{
MONITORINFO mi = { sizeof(mi) };
GetMonitorInfoW(mh, &mi);
SetWindowPos(window->win32.handle, HWND_TOP,
mi.rcWork.left,
mi.rcWork.top,
mi.rcWork.right - mi.rcWork.left,
mi.rcWork.bottom - mi.rcWork.top,
SWP_NOACTIVATE | SWP_NOZORDER);
}
}
DragAcceptFiles(window->win32.handle, TRUE);
@ -1355,53 +1452,10 @@ static int createNativeWindow(_GLFWwindow* window,
return GLFW_TRUE;
}
// Registers the GLFW window class
//
GLFWbool _glfwRegisterWindowClassWin32(void)
{
WNDCLASSEXW wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(wc);
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) windowProc;
wc.hInstance = GetModuleHandleW(NULL);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.lpszClassName = _GLFW_WNDCLASSNAME;
// Load user-provided icon if available
wc.hIcon = LoadImageW(GetModuleHandleW(NULL),
L"GLFW_ICON", IMAGE_ICON,
0, 0, LR_DEFAULTSIZE | LR_SHARED);
if (!wc.hIcon)
{
// No user-provided icon found, load default icon
wc.hIcon = LoadImageW(NULL,
IDI_APPLICATION, IMAGE_ICON,
0, 0, LR_DEFAULTSIZE | LR_SHARED);
}
if (!RegisterClassExW(&wc))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to register window class");
return GLFW_FALSE;
}
return GLFW_TRUE;
}
// Unregisters the GLFW window class
//
void _glfwUnregisterWindowClassWin32(void)
{
UnregisterClassW(_GLFW_WNDCLASSNAME, GetModuleHandleW(NULL));
}
int _glfwCreateWindowWin32(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
GLFWbool _glfwCreateWindowWin32(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
if (!createNativeWindow(window, wndconfig, fbconfig))
return GLFW_FALSE;
@ -1429,14 +1483,32 @@ int _glfwCreateWindowWin32(_GLFWwindow* window,
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
}
if (wndconfig->mousePassthrough)
_glfwSetWindowMousePassthroughWin32(window, GLFW_TRUE);
if (window->monitor)
{
_glfwShowWindowWin32(window);
_glfwFocusWindowWin32(window);
acquireMonitor(window);
fitToMonitor(window);
if (wndconfig->centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig->visible)
{
_glfwShowWindowWin32(window);
if (wndconfig->focused)
_glfwFocusWindowWin32(window);
}
}
return GLFW_TRUE;
@ -1451,7 +1523,10 @@ void _glfwDestroyWindowWin32(_GLFWwindow* window)
window->context.destroy(window);
if (_glfw.win32.disabledCursorWindow == window)
_glfw.win32.disabledCursorWindow = NULL;
enableCursor(window);
if (_glfw.win32.capturedCursorWindow == window)
releaseCursor();
if (window->win32.handle)
{
@ -1477,8 +1552,7 @@ void _glfwSetWindowTitleWin32(_GLFWwindow* window, const char* title)
_glfw_free(wideTitle);
}
void _glfwSetWindowIconWin32(_GLFWwindow* window,
int count, const GLFWimage* images)
void _glfwSetWindowIconWin32(_GLFWwindow* window, int count, const GLFWimage* images)
{
HICON bigIcon = NULL, smallIcon = NULL;
@ -1500,8 +1574,8 @@ void _glfwSetWindowIconWin32(_GLFWwindow* window,
smallIcon = (HICON) GetClassLongPtrW(window->win32.handle, GCLP_HICONSM);
}
SendMessage(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
SendMessage(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
SendMessageW(window->win32.handle, WM_SETICON, ICON_BIG, (LPARAM) bigIcon);
SendMessageW(window->win32.handle, WM_SETICON, ICON_SMALL, (LPARAM) smallIcon);
if (window->win32.bigIcon)
DestroyIcon(window->win32.bigIcon);
@ -1531,7 +1605,7 @@ void _glfwSetWindowPosWin32(_GLFWwindow* window, int xpos, int ypos)
{
RECT rect = { xpos, ypos, xpos, ypos };
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
@ -1572,7 +1646,7 @@ void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height)
{
RECT rect = { 0, 0, width, height };
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
@ -1591,8 +1665,8 @@ void _glfwSetWindowSizeWin32(_GLFWwindow* window, int width, int height)
}
void _glfwSetWindowSizeLimitsWin32(_GLFWwindow* window,
int minwidth, int minheight,
int maxwidth, int maxheight)
int minwidth, int minheight,
int maxwidth, int maxheight)
{
RECT area;
@ -1630,8 +1704,8 @@ void _glfwGetFramebufferSizeWin32(_GLFWwindow* window, int* width, int* height)
}
void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window,
int* left, int* top,
int* right, int* bottom)
int* left, int* top,
int* right, int* bottom)
{
RECT rect;
int width, height;
@ -1639,7 +1713,7 @@ void _glfwGetWindowFrameSizeWin32(_GLFWwindow* window,
_glfwGetWindowSizeWin32(window, &width, &height);
SetRect(&rect, 0, 0, width, height);
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
@ -1680,7 +1754,10 @@ void _glfwRestoreWindowWin32(_GLFWwindow* window)
void _glfwMaximizeWindowWin32(_GLFWwindow* window)
{
ShowWindow(window->win32.handle, SW_MAXIMIZE);
if (IsWindowVisible(window->win32.handle))
ShowWindow(window->win32.handle, SW_MAXIMIZE);
else
maximizeWindowManually(window);
}
void _glfwShowWindowWin32(_GLFWwindow* window)
@ -1725,7 +1802,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
{
RECT rect = { xpos, ypos, xpos + width, ypos + height };
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
@ -1767,7 +1844,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
acquireMonitor(window);
GetMonitorInfo(window->monitor->win32.handle, &mi);
GetMonitorInfoW(window->monitor->win32.handle, &mi);
SetWindowPos(window->win32.handle, HWND_TOPMOST,
mi.rcMonitor.left,
mi.rcMonitor.top,
@ -1796,7 +1873,7 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
else
after = HWND_NOTOPMOST;
if (_glfwIsWindows10AnniversaryUpdateOrGreaterWin32())
if (_glfwIsWindows10Version1607OrGreaterWin32())
{
AdjustWindowRectExForDpi(&rect, getWindowStyle(window),
FALSE, getWindowExStyle(window),
@ -1815,32 +1892,32 @@ void _glfwSetWindowMonitorWin32(_GLFWwindow* window,
}
}
int _glfwWindowFocusedWin32(_GLFWwindow* window)
GLFWbool _glfwWindowFocusedWin32(_GLFWwindow* window)
{
return window->win32.handle == GetActiveWindow();
}
int _glfwWindowIconifiedWin32(_GLFWwindow* window)
GLFWbool _glfwWindowIconifiedWin32(_GLFWwindow* window)
{
return IsIconic(window->win32.handle);
}
int _glfwWindowVisibleWin32(_GLFWwindow* window)
GLFWbool _glfwWindowVisibleWin32(_GLFWwindow* window)
{
return IsWindowVisible(window->win32.handle);
}
int _glfwWindowMaximizedWin32(_GLFWwindow* window)
GLFWbool _glfwWindowMaximizedWin32(_GLFWwindow* window)
{
return IsZoomed(window->win32.handle);
}
int _glfwWindowHoveredWin32(_GLFWwindow* window)
GLFWbool _glfwWindowHoveredWin32(_GLFWwindow* window)
{
return cursorInContentArea(window);
}
int _glfwFramebufferTransparentWin32(_GLFWwindow* window)
GLFWbool _glfwFramebufferTransparentWin32(_GLFWwindow* window)
{
BOOL composition, opaque;
DWORD color;
@ -2064,7 +2141,7 @@ void _glfwWaitEventsTimeoutWin32(double timeout)
void _glfwPostEmptyEventWin32(void)
{
PostMessage(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0);
PostMessageW(_glfw.win32.helperWindowHandle, WM_NULL, 0, 0);
}
void _glfwGetCursorPosWin32(_GLFWwindow* window, double* xpos, double* ypos)
@ -2096,14 +2173,40 @@ void _glfwSetCursorPosWin32(_GLFWwindow* window, double xpos, double ypos)
void _glfwSetCursorModeWin32(_GLFWwindow* window, int mode)
{
if (mode == GLFW_CURSOR_DISABLED)
if (_glfwWindowFocusedWin32(window))
{
if (_glfwWindowFocusedWin32(window))
disableCursor(window);
if (mode == GLFW_CURSOR_DISABLED)
{
_glfwGetCursorPosWin32(window,
&_glfw.win32.restoreCursorPosX,
&_glfw.win32.restoreCursorPosY);
_glfwCenterCursorInContentArea(window);
if (window->rawMouseMotion)
enableRawMouseMotion(window);
}
else if (_glfw.win32.disabledCursorWindow == window)
{
if (window->rawMouseMotion)
disableRawMouseMotion(window);
}
if (mode == GLFW_CURSOR_DISABLED || mode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
else
releaseCursor();
if (mode == GLFW_CURSOR_DISABLED)
_glfw.win32.disabledCursorWindow = window;
else if (_glfw.win32.disabledCursorWindow == window)
{
_glfw.win32.disabledCursorWindow = NULL;
_glfwSetCursorPosWin32(window,
_glfw.win32.restoreCursorPosX,
_glfw.win32.restoreCursorPosY);
}
}
else if (_glfw.win32.disabledCursorWindow == window)
enableCursor(window);
else if (cursorInContentArea(window))
if (cursorInContentArea(window))
updateCursorImage(window);
}
@ -2124,9 +2227,9 @@ int _glfwGetKeyScancodeWin32(int key)
return _glfw.win32.scancodes[key];
}
int _glfwCreateCursorWin32(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
GLFWbool _glfwCreateCursorWin32(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
{
cursor->win32.handle = (HCURSOR) createIcon(image, xhot, yhot, GLFW_FALSE);
if (!cursor->win32.handle)
@ -2135,7 +2238,7 @@ int _glfwCreateCursorWin32(_GLFWcursor* cursor,
return GLFW_TRUE;
}
int _glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape)
GLFWbool _glfwCreateStandardCursorWin32(_GLFWcursor* cursor, int shape)
{
int id = 0;
@ -2343,9 +2446,9 @@ void _glfwGetRequiredInstanceExtensionsWin32(char** extensions)
extensions[1] = "VK_KHR_win32_surface";
}
int _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
GLFWbool _glfwGetPhysicalDevicePresentationSupportWin32(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR
vkGetPhysicalDeviceWin32PresentationSupportKHR =
@ -2381,7 +2484,7 @@ VkResult _glfwCreateWindowSurfaceWin32(VkInstance instance,
memset(&sci, 0, sizeof(sci));
sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
sci.hinstance = GetModuleHandle(NULL);
sci.hinstance = _glfw.win32.instance;
sci.hwnd = window->win32.handle;
err = vkCreateWin32SurfaceKHR(instance, &sci, allocator, surface);
@ -2410,3 +2513,5 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
return window->win32.handle;
}
#endif // _GLFW_WIN32

View File

@ -44,6 +44,9 @@
//
void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused)
{
assert(window != NULL);
assert(focused == GLFW_TRUE || focused == GLFW_FALSE);
if (window->callbacks.focus)
window->callbacks.focus((GLFWwindow*) window, focused);
@ -73,6 +76,8 @@ void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused)
//
void _glfwInputWindowPos(_GLFWwindow* window, int x, int y)
{
assert(window != NULL);
if (window->callbacks.pos)
window->callbacks.pos((GLFWwindow*) window, x, y);
}
@ -82,6 +87,10 @@ void _glfwInputWindowPos(_GLFWwindow* window, int x, int y)
//
void _glfwInputWindowSize(_GLFWwindow* window, int width, int height)
{
assert(window != NULL);
assert(width >= 0);
assert(height >= 0);
if (window->callbacks.size)
window->callbacks.size((GLFWwindow*) window, width, height);
}
@ -90,6 +99,9 @@ void _glfwInputWindowSize(_GLFWwindow* window, int width, int height)
//
void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified)
{
assert(window != NULL);
assert(iconified == GLFW_TRUE || iconified == GLFW_FALSE);
if (window->callbacks.iconify)
window->callbacks.iconify((GLFWwindow*) window, iconified);
}
@ -98,6 +110,9 @@ void _glfwInputWindowIconify(_GLFWwindow* window, GLFWbool iconified)
//
void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized)
{
assert(window != NULL);
assert(maximized == GLFW_TRUE || maximized == GLFW_FALSE);
if (window->callbacks.maximize)
window->callbacks.maximize((GLFWwindow*) window, maximized);
}
@ -107,6 +122,10 @@ void _glfwInputWindowMaximize(_GLFWwindow* window, GLFWbool maximized)
//
void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height)
{
assert(window != NULL);
assert(width >= 0);
assert(height >= 0);
if (window->callbacks.fbsize)
window->callbacks.fbsize((GLFWwindow*) window, width, height);
}
@ -116,6 +135,12 @@ void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height)
//
void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscale)
{
assert(window != NULL);
assert(xscale > 0.f);
assert(xscale < FLT_MAX);
assert(yscale > 0.f);
assert(yscale < FLT_MAX);
if (window->callbacks.scale)
window->callbacks.scale((GLFWwindow*) window, xscale, yscale);
}
@ -124,6 +149,8 @@ void _glfwInputWindowContentScale(_GLFWwindow* window, float xscale, float yscal
//
void _glfwInputWindowDamage(_GLFWwindow* window)
{
assert(window != NULL);
if (window->callbacks.refresh)
window->callbacks.refresh((GLFWwindow*) window);
}
@ -132,6 +159,8 @@ void _glfwInputWindowDamage(_GLFWwindow* window)
//
void _glfwInputWindowCloseRequest(_GLFWwindow* window)
{
assert(window != NULL);
window->shouldClose = GLFW_TRUE;
if (window->callbacks.close)
@ -142,6 +171,7 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window)
//
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor)
{
assert(window != NULL);
window->monitor = monitor;
}
@ -215,40 +245,12 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height,
window->numer = GLFW_DONT_CARE;
window->denom = GLFW_DONT_CARE;
// Open the actual window and create its context
if (!_glfw.platform.createWindow(window, &wndconfig, &ctxconfig, &fbconfig))
{
glfwDestroyWindow((GLFWwindow*) window);
return NULL;
}
if (ctxconfig.client != GLFW_NO_API)
{
if (!_glfwRefreshContextAttribs(window, &ctxconfig))
{
glfwDestroyWindow((GLFWwindow*) window);
return NULL;
}
}
if (wndconfig.mousePassthrough)
_glfw.platform.setWindowMousePassthrough(window, GLFW_TRUE);
if (window->monitor)
{
if (wndconfig.centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig.visible)
{
_glfw.platform.showWindow(window);
if (wndconfig.focused)
_glfw.platform.focusWindow(window);
}
}
return (GLFWwindow*) window;
}
@ -272,6 +274,8 @@ void glfwDefaultWindowHints(void)
_glfw.hints.window.autoIconify = GLFW_TRUE;
_glfw.hints.window.centerCursor = GLFW_TRUE;
_glfw.hints.window.focusOnShow = GLFW_TRUE;
_glfw.hints.window.xpos = GLFW_ANY_POSITION;
_glfw.hints.window.ypos = GLFW_ANY_POSITION;
// The default is 24 bits of color, 24 bits of depth and 8 bits of stencil,
// double buffered
@ -366,6 +370,12 @@ GLFWAPI void glfwWindowHint(int hint, int value)
case GLFW_VISIBLE:
_glfw.hints.window.visible = value ? GLFW_TRUE : GLFW_FALSE;
return;
case GLFW_POSITION_X:
_glfw.hints.window.xpos = value;
return;
case GLFW_POSITION_Y:
_glfw.hints.window.ypos = value;
return;
case GLFW_COCOA_RETINA_FRAMEBUFFER:
_glfw.hints.window.ns.retina = value ? GLFW_TRUE : GLFW_FALSE;
return;
@ -445,6 +455,10 @@ GLFWAPI void glfwWindowHintString(int hint, const char* value)
strncpy(_glfw.hints.window.x11.instanceName, value,
sizeof(_glfw.hints.window.x11.instanceName) - 1);
return;
case GLFW_WAYLAND_APP_ID:
strncpy(_glfw.hints.window.wl.appId, value,
sizeof(_glfw.hints.window.wl.appId) - 1);
return;
}
_glfwInputError(GLFW_INVALID_ENUM, "Invalid window hint string 0x%08X", hint);
@ -514,12 +528,33 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* handle, const char* title)
GLFWAPI void glfwSetWindowIcon(GLFWwindow* handle,
int count, const GLFWimage* images)
{
int i;
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
assert(count >= 0);
assert(count == 0 || images != NULL);
_GLFW_REQUIRE_INIT();
if (count < 0)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid image count for window icon");
return;
}
for (i = 0; i < count; i++)
{
assert(images[i].pixels != NULL);
if (images[i].width <= 0 || images[i].height <= 0)
{
_glfwInputError(GLFW_INVALID_VALUE,
"Invalid image dimensions for window icon");
return;
}
}
_glfw.platform.setWindowIcon(window, count, images);
}

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,8 @@
#include "internal.h"
#if defined(_GLFW_WAYLAND)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -37,7 +39,7 @@
#include "wayland-client-protocol.h"
static void outputHandleGeometry(void* data,
static void outputHandleGeometry(void* userData,
struct wl_output* output,
int32_t x,
int32_t y,
@ -48,24 +50,25 @@ static void outputHandleGeometry(void* data,
const char* model,
int32_t transform)
{
struct _GLFWmonitor *monitor = data;
struct _GLFWmonitor* monitor = userData;
monitor->wl.x = x;
monitor->wl.y = y;
monitor->widthMM = physicalWidth;
monitor->heightMM = physicalHeight;
snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model);
if (strlen(monitor->name) == 0)
snprintf(monitor->name, sizeof(monitor->name), "%s %s", make, model);
}
static void outputHandleMode(void* data,
static void outputHandleMode(void* userData,
struct wl_output* output,
uint32_t flags,
int32_t width,
int32_t height,
int32_t refresh)
{
struct _GLFWmonitor *monitor = data;
struct _GLFWmonitor* monitor = userData;
GLFWvidmode mode;
mode.width = width;
@ -84,9 +87,9 @@ static void outputHandleMode(void* data,
monitor->wl.currentMode = monitor->modeCount - 1;
}
static void outputHandleDone(void* data, struct wl_output* output)
static void outputHandleDone(void* userData, struct wl_output* output)
{
struct _GLFWmonitor *monitor = data;
struct _GLFWmonitor* monitor = userData;
if (monitor->widthMM <= 0 || monitor->heightMM <= 0)
{
@ -96,23 +99,63 @@ static void outputHandleDone(void* data, struct wl_output* output)
monitor->heightMM = (int) (mode->height * 25.4f / 96.f);
}
for (int i = 0; i < _glfw.monitorCount; i++)
{
if (_glfw.monitors[i] == monitor)
return;
}
_glfwInputMonitor(monitor, GLFW_CONNECTED, _GLFW_INSERT_LAST);
}
static void outputHandleScale(void* data,
static void outputHandleScale(void* userData,
struct wl_output* output,
int32_t factor)
{
struct _GLFWmonitor *monitor = data;
struct _GLFWmonitor* monitor = userData;
monitor->wl.scale = factor;
for (_GLFWwindow* window = _glfw.windowListHead; window; window = window->next)
{
for (int i = 0; i < window->wl.monitorsCount; i++)
{
if (window->wl.monitors[i] == monitor)
{
_glfwUpdateContentScaleWayland(window);
break;
}
}
}
}
static const struct wl_output_listener outputListener = {
#ifdef WL_OUTPUT_NAME_SINCE_VERSION
void outputHandleName(void* userData, struct wl_output* wl_output, const char* name)
{
struct _GLFWmonitor* monitor = userData;
strncpy(monitor->name, name, sizeof(monitor->name) - 1);
}
void outputHandleDescription(void* userData,
struct wl_output* wl_output,
const char* description)
{
}
#endif // WL_OUTPUT_NAME_SINCE_VERSION
static const struct wl_output_listener outputListener =
{
outputHandleGeometry,
outputHandleMode,
outputHandleDone,
outputHandleScale,
#ifdef WL_OUTPUT_NAME_SINCE_VERSION
outputHandleName,
outputHandleDescription,
#endif
};
@ -122,9 +165,6 @@ static const struct wl_output_listener outputListener = {
void _glfwAddOutputWayland(uint32_t name, uint32_t version)
{
_GLFWmonitor *monitor;
struct wl_output *output;
if (version < 2)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
@ -132,19 +172,21 @@ void _glfwAddOutputWayland(uint32_t name, uint32_t version)
return;
}
// The actual name of this output will be set in the geometry handler.
monitor = _glfwAllocMonitor("", 0, 0);
#ifdef WL_OUTPUT_NAME_SINCE_VERSION
version = _glfw_min(version, WL_OUTPUT_NAME_SINCE_VERSION);
#else
version = 2;
#endif
output = wl_registry_bind(_glfw.wl.registry,
name,
&wl_output_interface,
2);
struct wl_output* output = wl_registry_bind(_glfw.wl.registry,
name,
&wl_output_interface,
version);
if (!output)
{
_glfwFreeMonitor(monitor);
return;
}
// The actual name of this output will be set in the geometry handler
_GLFWmonitor* monitor = _glfwAllocMonitor("", 0, 0);
monitor->wl.scale = 1;
monitor->wl.output = output;
monitor->wl.name = name;
@ -230,3 +272,5 @@ GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* handle)
return monitor->wl.output;
}
#endif // _GLFW_WAYLAND

View File

@ -43,11 +43,12 @@ typedef VkResult (APIENTRY *PFN_vkCreateWaylandSurfaceKHR)(VkInstance,const VkWa
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR)(VkPhysicalDevice,uint32_t,struct wl_display*);
#include "xkb_unicode.h"
#include "posix_poll.h"
typedef int (* PFN_wl_display_flush)(struct wl_display *display);
typedef void (* PFN_wl_display_cancel_read)(struct wl_display *display);
typedef int (* PFN_wl_display_dispatch_pending)(struct wl_display *display);
typedef int (* PFN_wl_display_read_events)(struct wl_display *display);
typedef int (* PFN_wl_display_flush)(struct wl_display* display);
typedef void (* PFN_wl_display_cancel_read)(struct wl_display* display);
typedef int (* PFN_wl_display_dispatch_pending)(struct wl_display* display);
typedef int (* PFN_wl_display_read_events)(struct wl_display* display);
typedef struct wl_display* (* PFN_wl_display_connect)(const char*);
typedef void (* PFN_wl_display_disconnect)(struct wl_display*);
typedef int (* PFN_wl_display_roundtrip)(struct wl_display*);
@ -166,8 +167,8 @@ typedef struct xkb_state* (* PFN_xkb_state_new)(struct xkb_keymap*);
typedef void (* PFN_xkb_state_unref)(struct xkb_state*);
typedef int (* PFN_xkb_state_key_get_syms)(struct xkb_state*, xkb_keycode_t, const xkb_keysym_t**);
typedef enum xkb_state_component (* PFN_xkb_state_update_mask)(struct xkb_state*, xkb_mod_mask_t, xkb_mod_mask_t, xkb_mod_mask_t, xkb_layout_index_t, xkb_layout_index_t, xkb_layout_index_t);
typedef xkb_mod_mask_t (* PFN_xkb_state_serialize_mods)(struct xkb_state*, enum xkb_state_component);
typedef xkb_layout_index_t (* PFN_xkb_state_key_get_layout)(struct xkb_state*,xkb_keycode_t);
typedef int (* PFN_xkb_state_mod_index_is_active)(struct xkb_state*,xkb_mod_index_t,enum xkb_state_component);
#define xkb_context_new _glfw.wl.xkb.context_new
#define xkb_context_unref _glfw.wl.xkb.context_unref
#define xkb_keymap_new_from_string _glfw.wl.xkb.keymap_new_from_string
@ -179,8 +180,8 @@ typedef xkb_layout_index_t (* PFN_xkb_state_key_get_layout)(struct xkb_state*,xk
#define xkb_state_unref _glfw.wl.xkb.state_unref
#define xkb_state_key_get_syms _glfw.wl.xkb.state_key_get_syms
#define xkb_state_update_mask _glfw.wl.xkb.state_update_mask
#define xkb_state_serialize_mods _glfw.wl.xkb.state_serialize_mods
#define xkb_state_key_get_layout _glfw.wl.xkb.state_key_get_layout
#define xkb_state_mod_index_is_active _glfw.wl.xkb.state_mod_index_is_active
typedef struct xkb_compose_table* (* PFN_xkb_compose_table_new_from_locale)(struct xkb_context*, const char*, enum xkb_compose_compile_flags);
typedef void (* PFN_xkb_compose_table_unref)(struct xkb_compose_table*);
@ -197,11 +198,6 @@ typedef xkb_keysym_t (* PFN_xkb_compose_state_get_one_sym)(struct xkb_compose_st
#define xkb_compose_state_get_status _glfw.wl.xkb.compose_state_get_status
#define xkb_compose_state_get_one_sym _glfw.wl.xkb.compose_state_get_one_sym
#define _GLFW_DECORATION_WIDTH 4
#define _GLFW_DECORATION_TOP 24
#define _GLFW_DECORATION_VERTICAL (_GLFW_DECORATION_TOP + _GLFW_DECORATION_WIDTH)
#define _GLFW_DECORATION_HORIZONTAL (2 * _GLFW_DECORATION_WIDTH)
typedef enum _GLFWdecorationSideWayland
{
mainWindow,
@ -218,6 +214,13 @@ typedef struct _GLFWdecorationWayland
struct wp_viewport* viewport;
} _GLFWdecorationWayland;
typedef struct _GLFWofferWayland
{
struct wl_data_offer* offer;
GLFWbool text_plain_utf8;
GLFWbool text_uri_list;
} _GLFWofferWayland;
// Wayland-specific per-window data
//
typedef struct _GLFWwindowWayland
@ -225,22 +228,37 @@ typedef struct _GLFWwindowWayland
int width, height;
GLFWbool visible;
GLFWbool maximized;
GLFWbool activated;
GLFWbool fullscreen;
GLFWbool hovered;
GLFWbool transparent;
struct wl_surface* surface;
struct wl_egl_window* native;
struct wl_callback* callback;
struct {
struct wl_egl_window* window;
} egl;
struct {
int width, height;
GLFWbool maximized;
GLFWbool iconified;
GLFWbool activated;
GLFWbool fullscreen;
} pending;
struct {
struct xdg_surface* surface;
struct xdg_toplevel* toplevel;
struct zxdg_toplevel_decoration_v1* decoration;
uint32_t decorationMode;
} xdg;
_GLFWcursor* currentCursor;
double cursorPosX, cursorPosY;
char* title;
char* appId;
// We need to track the monitors the window spans on to calculate the
// optimal scaling factor.
@ -249,20 +267,16 @@ typedef struct _GLFWwindowWayland
int monitorsCount;
int monitorsSize;
struct {
struct zwp_relative_pointer_v1* relativePointer;
struct zwp_locked_pointer_v1* lockedPointer;
} pointerLock;
struct zwp_relative_pointer_v1* relativePointer;
struct zwp_locked_pointer_v1* lockedPointer;
struct zwp_confined_pointer_v1* confinedPointer;
struct zwp_idle_inhibitor_v1* idleInhibitor;
GLFWbool wasFullscreen;
struct {
GLFWbool serverSide;
struct wl_buffer* buffer;
_GLFWdecorationWayland top, left, right, bottom;
int focus;
_GLFWdecorationSideWayland focus;
} decorations;
} _GLFWwindowWayland;
@ -280,8 +294,6 @@ typedef struct _GLFWlibraryWayland
struct wl_keyboard* keyboard;
struct wl_data_device_manager* dataDeviceManager;
struct wl_data_device* dataDevice;
struct wl_data_offer* dataOffer;
struct wl_data_source* dataSource;
struct xdg_wm_base* wmBase;
struct zxdg_decoration_manager_v1* decorationManager;
struct wp_viewporter* viewporter;
@ -289,6 +301,16 @@ typedef struct _GLFWlibraryWayland
struct zwp_pointer_constraints_v1* pointerConstraints;
struct zwp_idle_inhibit_manager_v1* idleInhibitManager;
_GLFWofferWayland* offers;
unsigned int offerCount;
struct wl_data_offer* selectionOffer;
struct wl_data_source* selectionSource;
struct wl_data_offer* dragOffer;
_GLFWwindow* dragFocus;
uint32_t dragSerial;
int compositorVersion;
int seatVersion;
@ -300,15 +322,12 @@ typedef struct _GLFWlibraryWayland
uint32_t serial;
uint32_t pointerEnterSerial;
int32_t keyboardRepeatRate;
int32_t keyboardRepeatDelay;
int keyboardLastKey;
int keyboardLastScancode;
int keyRepeatTimerfd;
int32_t keyRepeatRate;
int32_t keyRepeatDelay;
int keyRepeatScancode;
char* clipboardString;
size_t clipboardSize;
char* clipboardSendString;
size_t clipboardSendSize;
int timerfd;
short int keycodes[256];
short int scancodes[GLFW_KEY_LAST + 1];
char keynames[GLFW_KEY_LAST + 1][5];
@ -321,12 +340,12 @@ typedef struct _GLFWlibraryWayland
struct xkb_compose_state* composeState;
xkb_mod_mask_t controlMask;
xkb_mod_mask_t altMask;
xkb_mod_mask_t shiftMask;
xkb_mod_mask_t superMask;
xkb_mod_mask_t capsLockMask;
xkb_mod_mask_t numLockMask;
xkb_mod_index_t controlIndex;
xkb_mod_index_t altIndex;
xkb_mod_index_t shiftIndex;
xkb_mod_index_t superIndex;
xkb_mod_index_t capsLockIndex;
xkb_mod_index_t numLockIndex;
unsigned int modifiers;
PFN_xkb_context_new context_new;
@ -340,8 +359,8 @@ typedef struct _GLFWlibraryWayland
PFN_xkb_state_unref state_unref;
PFN_xkb_state_key_get_syms state_key_get_syms;
PFN_xkb_state_update_mask state_update_mask;
PFN_xkb_state_serialize_mods state_serialize_mods;
PFN_xkb_state_key_get_layout state_key_get_layout;
PFN_xkb_state_mod_index_is_active state_mod_index_is_active;
PFN_xkb_compose_table_new_from_locale compose_table_new_from_locale;
PFN_xkb_compose_table_unref compose_table_unref;
@ -423,7 +442,7 @@ GLFWbool _glfwConnectWayland(int platformID, _GLFWplatform* platform);
int _glfwInitWayland(void);
void _glfwTerminateWayland(void);
int _glfwCreateWindowWayland(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
GLFWbool _glfwCreateWindowWayland(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
void _glfwDestroyWindowWayland(_GLFWwindow* window);
void _glfwSetWindowTitleWayland(_GLFWwindow* window, const char* title);
void _glfwSetWindowIconWayland(_GLFWwindow* window, int count, const GLFWimage* images);
@ -444,12 +463,12 @@ void _glfwHideWindowWayland(_GLFWwindow* window);
void _glfwRequestWindowAttentionWayland(_GLFWwindow* window);
void _glfwFocusWindowWayland(_GLFWwindow* window);
void _glfwSetWindowMonitorWayland(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate);
int _glfwWindowFocusedWayland(_GLFWwindow* window);
int _glfwWindowIconifiedWayland(_GLFWwindow* window);
int _glfwWindowVisibleWayland(_GLFWwindow* window);
int _glfwWindowMaximizedWayland(_GLFWwindow* window);
int _glfwWindowHoveredWayland(_GLFWwindow* window);
int _glfwFramebufferTransparentWayland(_GLFWwindow* window);
GLFWbool _glfwWindowFocusedWayland(_GLFWwindow* window);
GLFWbool _glfwWindowIconifiedWayland(_GLFWwindow* window);
GLFWbool _glfwWindowVisibleWayland(_GLFWwindow* window);
GLFWbool _glfwWindowMaximizedWayland(_GLFWwindow* window);
GLFWbool _glfwWindowHoveredWayland(_GLFWwindow* window);
GLFWbool _glfwFramebufferTransparentWayland(_GLFWwindow* window);
void _glfwSetWindowResizableWayland(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowDecoratedWayland(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowFloatingWayland(_GLFWwindow* window, GLFWbool enabled);
@ -457,7 +476,7 @@ float _glfwGetWindowOpacityWayland(_GLFWwindow* window);
void _glfwSetWindowOpacityWayland(_GLFWwindow* window, float opacity);
void _glfwSetWindowMousePassthroughWayland(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetRawMouseMotionWayland(_GLFWwindow *window, GLFWbool enabled);
void _glfwSetRawMouseMotionWayland(_GLFWwindow* window, GLFWbool enabled);
GLFWbool _glfwRawMouseMotionSupportedWayland(void);
void _glfwPollEventsWayland(void);
@ -470,8 +489,8 @@ void _glfwSetCursorPosWayland(_GLFWwindow* window, double xpos, double ypos);
void _glfwSetCursorModeWayland(_GLFWwindow* window, int mode);
const char* _glfwGetScancodeNameWayland(int scancode);
int _glfwGetKeyScancodeWayland(int key);
int _glfwCreateCursorWayland(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
int _glfwCreateStandardCursorWayland(_GLFWcursor* cursor, int shape);
GLFWbool _glfwCreateCursorWayland(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
GLFWbool _glfwCreateStandardCursorWayland(_GLFWcursor* cursor, int shape);
void _glfwDestroyCursorWayland(_GLFWcursor* cursor);
void _glfwSetCursorWayland(_GLFWwindow* window, _GLFWcursor* cursor);
void _glfwSetClipboardStringWayland(const char* string);
@ -482,7 +501,7 @@ EGLNativeDisplayType _glfwGetEGLNativeDisplayWayland(void);
EGLNativeWindowType _glfwGetEGLNativeWindowWayland(_GLFWwindow* window);
void _glfwGetRequiredInstanceExtensionsWayland(char** extensions);
int _glfwGetPhysicalDevicePresentationSupportWayland(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
GLFWbool _glfwGetPhysicalDevicePresentationSupportWayland(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceWayland(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
void _glfwFreeMonitorWayland(_GLFWmonitor* monitor);
@ -495,5 +514,8 @@ GLFWbool _glfwGetGammaRampWayland(_GLFWmonitor* monitor, GLFWgammaramp* ramp);
void _glfwSetGammaRampWayland(_GLFWmonitor* monitor, const GLFWgammaramp* ramp);
void _glfwAddOutputWayland(uint32_t name, uint32_t version);
GLFWbool _glfwInputTextWayland(_GLFWwindow* window, uint32_t scancode);
void _glfwUpdateContentScaleWayland(_GLFWwindow* window);
void _glfwAddSeatListenerWayland(struct wl_seat* seat);
void _glfwAddDataDeviceListenerWayland(struct wl_data_device* device);

File diff suppressed because it is too large Load Diff

View File

@ -29,12 +29,17 @@
#include "internal.h"
#if defined(_GLFW_X11)
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdio.h>
#include <locale.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
// Translate the X11 KeySyms for a key to a GLFW key code
@ -601,7 +606,7 @@ static void detectEWMH(void)
//
static GLFWbool initExtensions(void)
{
#if defined(__OpenBSD__)
#if defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so");
#else
_glfw.x11.vidmode.handle = _glfwPlatformLoadModule("libXxf86vm.so.1");
@ -625,7 +630,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__)
_glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi-6.so");
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so");
#else
_glfw.x11.xi.handle = _glfwPlatformLoadModule("libXi.so.6");
@ -657,7 +662,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__)
_glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr-2.so");
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so");
#else
_glfw.x11.randr.handle = _glfwPlatformLoadModule("libXrandr.so.2");
@ -751,7 +756,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__)
_glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor-1.so");
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so");
#else
_glfw.x11.xcursor.handle = _glfwPlatformLoadModule("libXcursor.so.1");
@ -774,7 +779,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__)
_glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama-1.so");
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so");
#else
_glfw.x11.xinerama.handle = _glfwPlatformLoadModule("libXinerama.so.1");
@ -829,7 +834,7 @@ static GLFWbool initExtensions(void)
{
#if defined(__CYGWIN__)
_glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb-1.so");
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so");
#else
_glfw.x11.x11xcb.handle = _glfwPlatformLoadModule("libX11-xcb.so.1");
@ -844,7 +849,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__)
_glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender-1.so");
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so");
#else
_glfw.x11.xrender.handle = _glfwPlatformLoadModule("libXrender.so.1");
@ -873,7 +878,7 @@ static GLFWbool initExtensions(void)
#if defined(__CYGWIN__)
_glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext-6.so");
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
_glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so");
#else
_glfw.x11.xshape.handle = _glfwPlatformLoadModule("libXext.so.6");
@ -1042,6 +1047,37 @@ static Window createHelperWindow(void)
CWEventMask, &wa);
}
// Create the pipe for empty events without assumuing the OS has pipe2(2)
//
static GLFWbool createEmptyEventPipe(void)
{
if (pipe(_glfw.x11.emptyEventPipe) != 0)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to create empty event pipe: %s",
strerror(errno));
return GLFW_FALSE;
}
for (int i = 0; i < 2; i++)
{
const int sf = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFL, 0);
const int df = fcntl(_glfw.x11.emptyEventPipe[i], F_GETFD, 0);
if (sf == -1 || df == -1 ||
fcntl(_glfw.x11.emptyEventPipe[i], F_SETFL, sf | O_NONBLOCK) == -1 ||
fcntl(_glfw.x11.emptyEventPipe[i], F_SETFD, df | FD_CLOEXEC) == -1)
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: Failed to set flags for empty event pipe: %s",
strerror(errno));
return GLFW_FALSE;
}
}
return GLFW_TRUE;
}
// X error handler
//
static int errorHandler(Display *display, XErrorEvent* event)
@ -1062,8 +1098,9 @@ static int errorHandler(Display *display, XErrorEvent* event)
//
void _glfwGrabErrorHandlerX11(void)
{
assert(_glfw.x11.errorHandler == NULL);
_glfw.x11.errorCode = Success;
XSetErrorHandler(errorHandler);
_glfw.x11.errorHandler = XSetErrorHandler(errorHandler);
}
// Clears the X error handler callback
@ -1072,7 +1109,8 @@ void _glfwReleaseErrorHandlerX11(void)
{
// Synchronize to make sure all commands are processed
XSync(_glfw.x11.display, False);
XSetErrorHandler(NULL);
XSetErrorHandler(_glfw.x11.errorHandler);
_glfw.x11.errorHandler = NULL;
}
// Reports the specified error, appending information about the last X error
@ -1146,7 +1184,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
_glfwGetKeyScancodeX11,
_glfwSetClipboardStringX11,
_glfwGetClipboardStringX11,
#if defined(__linux__)
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
_glfwInitJoysticksLinux,
_glfwTerminateJoysticksLinux,
_glfwPollJoystickLinux,
@ -1221,7 +1259,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform)
#if defined(__CYGWIN__)
void* module = _glfwPlatformLoadModule("libX11-6.so");
#elif defined(__OpenBSD__)
#elif defined(__OpenBSD__) || defined(__NetBSD__)
void* module = _glfwPlatformLoadModule("libX11.so");
#else
void* module = _glfwPlatformLoadModule("libX11.so.6");
@ -1491,6 +1529,9 @@ int _glfwInitX11(void)
getSystemContentScale(&_glfw.x11.contentScaleX, &_glfw.x11.contentScaleY);
if (!createEmptyEventPipe())
return GLFW_FALSE;
if (!initExtensions())
return GLFW_FALSE;
@ -1594,6 +1635,7 @@ void _glfwTerminateX11(void)
_glfw.x11.xi.handle = NULL;
}
_glfwTerminateOSMesa();
// NOTE: These need to be unloaded after XCloseDisplay, as they register
// cleanup callbacks that get called by that function
_glfwTerminateEGL();
@ -1604,5 +1646,13 @@ void _glfwTerminateX11(void)
_glfwPlatformFreeModule(_glfw.x11.xlib.handle);
_glfw.x11.xlib.handle = NULL;
}
if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1])
{
close(_glfw.x11.emptyEventPipe[0]);
close(_glfw.x11.emptyEventPipe[1]);
}
}
#endif // _GLFW_X11

View File

@ -29,6 +29,8 @@
#include "internal.h"
#if defined(_GLFW_X11)
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@ -614,3 +616,5 @@ GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* handle)
return monitor->x11.output;
}
#endif // _GLFW_X11

View File

@ -453,6 +453,7 @@ typedef VkResult (APIENTRY *PFN_vkCreateXcbSurfaceKHR)(VkInstance,const VkXcbSur
typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR)(VkPhysicalDevice,uint32_t,xcb_connection_t*,xcb_visualid_t);
#include "xkb_unicode.h"
#include "posix_poll.h"
#define GLFW_X11_WINDOW_STATE _GLFWwindowX11 x11;
#define GLFW_X11_LIBRARY_WINDOW_STATE _GLFWlibraryX11 x11;
@ -479,7 +480,6 @@ typedef struct _GLFWlibraryGLX
int eventBase;
int errorBase;
// dlopen handle for libGL.so.1
void* handle;
// GLX 1.3 functions
@ -566,6 +566,8 @@ typedef struct _GLFWlibraryX11
XContext context;
// XIM input method
XIM im;
// The previous X error handler, to be restored later
XErrorHandler errorHandler;
// Most recent error code received by X error handler
int errorCode;
// Primary selection string (while the primary selection is owned)
@ -582,6 +584,7 @@ typedef struct _GLFWlibraryX11
double restoreCursorPosX, restoreCursorPosY;
// The window whose disabled cursor mode is active
_GLFWwindow* disabledCursorWindow;
int emptyEventPipe[2];
// Window manager atoms
Atom NET_SUPPORTED;
@ -898,7 +901,7 @@ GLFWbool _glfwConnectX11(int platformID, _GLFWplatform* platform);
int _glfwInitX11(void);
void _glfwTerminateX11(void);
int _glfwCreateWindowX11(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
GLFWbool _glfwCreateWindowX11(_GLFWwindow* window, const _GLFWwndconfig* wndconfig, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig);
void _glfwDestroyWindowX11(_GLFWwindow* window);
void _glfwSetWindowTitleX11(_GLFWwindow* window, const char* title);
void _glfwSetWindowIconX11(_GLFWwindow* window, int count, const GLFWimage* images);
@ -919,12 +922,12 @@ void _glfwHideWindowX11(_GLFWwindow* window);
void _glfwRequestWindowAttentionX11(_GLFWwindow* window);
void _glfwFocusWindowX11(_GLFWwindow* window);
void _glfwSetWindowMonitorX11(_GLFWwindow* window, _GLFWmonitor* monitor, int xpos, int ypos, int width, int height, int refreshRate);
int _glfwWindowFocusedX11(_GLFWwindow* window);
int _glfwWindowIconifiedX11(_GLFWwindow* window);
int _glfwWindowVisibleX11(_GLFWwindow* window);
int _glfwWindowMaximizedX11(_GLFWwindow* window);
int _glfwWindowHoveredX11(_GLFWwindow* window);
int _glfwFramebufferTransparentX11(_GLFWwindow* window);
GLFWbool _glfwWindowFocusedX11(_GLFWwindow* window);
GLFWbool _glfwWindowIconifiedX11(_GLFWwindow* window);
GLFWbool _glfwWindowVisibleX11(_GLFWwindow* window);
GLFWbool _glfwWindowMaximizedX11(_GLFWwindow* window);
GLFWbool _glfwWindowHoveredX11(_GLFWwindow* window);
GLFWbool _glfwFramebufferTransparentX11(_GLFWwindow* window);
void _glfwSetWindowResizableX11(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowDecoratedX11(_GLFWwindow* window, GLFWbool enabled);
void _glfwSetWindowFloatingX11(_GLFWwindow* window, GLFWbool enabled);
@ -945,8 +948,8 @@ void _glfwSetCursorPosX11(_GLFWwindow* window, double xpos, double ypos);
void _glfwSetCursorModeX11(_GLFWwindow* window, int mode);
const char* _glfwGetScancodeNameX11(int scancode);
int _glfwGetKeyScancodeX11(int key);
int _glfwCreateCursorX11(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
int _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape);
GLFWbool _glfwCreateCursorX11(_GLFWcursor* cursor, const GLFWimage* image, int xhot, int yhot);
GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape);
void _glfwDestroyCursorX11(_GLFWcursor* cursor);
void _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor);
void _glfwSetClipboardStringX11(const char* string);
@ -957,7 +960,7 @@ EGLNativeDisplayType _glfwGetEGLNativeDisplayX11(void);
EGLNativeWindowType _glfwGetEGLNativeWindowX11(_GLFWwindow* window);
void _glfwGetRequiredInstanceExtensionsX11(char** extensions);
int _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance, VkPhysicalDevice device, uint32_t queuefamily);
VkResult _glfwCreateWindowSurfaceX11(VkInstance instance, _GLFWwindow* window, const VkAllocationCallbacks* allocator, VkSurfaceKHR* surface);
void _glfwFreeMonitorX11(_GLFWmonitor* monitor);

View File

@ -29,10 +29,12 @@
#include "internal.h"
#if defined(_GLFW_X11)
#include <X11/cursorfont.h>
#include <X11/Xmd.h>
#include <sys/select.h>
#include <poll.h>
#include <string.h>
#include <stdio.h>
@ -56,50 +58,79 @@
#define _GLFW_XDND_VERSION 5
// Wait for data to arrive using select
// Wait for event data to arrive on the X11 display socket
// This avoids blocking other threads via the per-display Xlib lock that also
// covers GLX functions
//
static GLFWbool waitForEvent(double* timeout)
static GLFWbool waitForX11Event(double* timeout)
{
fd_set fds;
const int fd = ConnectionNumber(_glfw.x11.display);
int count = fd + 1;
struct pollfd fd = { ConnectionNumber(_glfw.x11.display), POLLIN };
#if defined(__linux__)
if (_glfw.linjs.inotify > fd)
count = _glfw.linjs.inotify + 1;
while (!XPending(_glfw.x11.display))
{
if (!_glfwPollPOSIX(&fd, 1, timeout))
return GLFW_FALSE;
}
return GLFW_TRUE;
}
// Wait for event data to arrive on any event file descriptor
// This avoids blocking other threads via the per-display Xlib lock that also
// covers GLX functions
//
static GLFWbool waitForAnyEvent(double* timeout)
{
nfds_t count = 2;
struct pollfd fds[3] =
{
{ ConnectionNumber(_glfw.x11.display), POLLIN },
{ _glfw.x11.emptyEventPipe[0], POLLIN }
};
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
if (_glfw.joysticksInitialized)
fds[count++] = (struct pollfd) { _glfw.linjs.inotify, POLLIN };
#endif
while (!XPending(_glfw.x11.display))
{
if (!_glfwPollPOSIX(fds, count, timeout))
return GLFW_FALSE;
for (int i = 1; i < count; i++)
{
if (fds[i].revents & POLLIN)
return GLFW_TRUE;
}
}
return GLFW_TRUE;
}
// Writes a byte to the empty event pipe
//
static void writeEmptyEvent(void)
{
for (;;)
{
FD_ZERO(&fds);
FD_SET(fd, &fds);
#if defined(__linux__)
if (_glfw.linjs.inotify > 0)
FD_SET(_glfw.linjs.inotify, &fds);
#endif
const char byte = 0;
const ssize_t result = write(_glfw.x11.emptyEventPipe[1], &byte, 1);
if (result == 1 || (result == -1 && errno != EINTR))
break;
}
}
if (timeout)
{
const long seconds = (long) *timeout;
const long microseconds = (long) ((*timeout - seconds) * 1e6);
struct timeval tv = { seconds, microseconds };
const uint64_t base = _glfwPlatformGetTimerValue();
const int result = select(count, &fds, NULL, NULL, &tv);
const int error = errno;
*timeout -= (_glfwPlatformGetTimerValue() - base) /
(double) _glfwPlatformGetTimerFrequency();
if (result > 0)
return GLFW_TRUE;
if ((result == -1 && error == EINTR) || *timeout <= 0.0)
return GLFW_FALSE;
}
else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR)
return GLFW_TRUE;
// Drains available data from the empty event pipe
//
static void drainEmptyEvents(void)
{
for (;;)
{
char dummy[64];
const ssize_t result = read(_glfw.x11.emptyEventPipe[0], dummy, sizeof(dummy));
if (result == -1 && errno != EINTR)
break;
}
}
@ -116,7 +147,7 @@ static GLFWbool waitForVisibilityNotify(_GLFWwindow* window)
VisibilityNotify,
&dummy))
{
if (!waitForEvent(&timeout))
if (!waitForX11Event(&timeout))
return GLFW_FALSE;
}
@ -241,6 +272,11 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height)
{
XSizeHints* hints = XAllocSizeHints();
long supplied;
XGetWMNormalHints(_glfw.x11.display, window->x11.handle, hints, &supplied);
hints->flags &= ~(PMinSize | PMaxSize | PAspect);
if (!window->monitor)
{
if (window->resizable)
@ -277,9 +313,6 @@ static void updateNormalHints(_GLFWwindow* window, int width, int height)
}
}
hints->flags |= PWinGravity;
hints->win_gravity = StaticGravity;
XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
XFree(hints);
}
@ -378,57 +411,6 @@ static void updateWindowMode(_GLFWwindow* window)
}
}
// Splits and translates a text/uri-list into separate file paths
// NOTE: This function destroys the provided string
//
static char** parseUriList(char* text, int* count)
{
const char* prefix = "file://";
char** paths = NULL;
char* line;
*count = 0;
while ((line = strtok(text, "\r\n")))
{
text = NULL;
if (line[0] == '#')
continue;
if (strncmp(line, prefix, strlen(prefix)) == 0)
{
line += strlen(prefix);
// TODO: Validate hostname
while (*line != '/')
line++;
}
(*count)++;
char* path = _glfw_calloc(strlen(line) + 1, 1);
paths = _glfw_realloc(paths, *count * sizeof(char*));
paths[*count - 1] = path;
while (*line)
{
if (line[0] == '%' && line[1] && line[2])
{
const char digits[3] = { line[1], line[2], '\0' };
*path = strtol(digits, NULL, 16);
line += 2;
}
else
*path = *line;
path++;
line++;
}
}
return paths;
}
// Decode a Unicode code point from a UTF-8 stream
// Based on cutef8 by Jeff Bezanson (Public Domain)
//
@ -475,7 +457,8 @@ static char* convertLatin1toUTF8(const char* source)
//
static void updateCursorImage(_GLFWwindow* window)
{
if (window->cursorMode == GLFW_CURSOR_NORMAL)
if (window->cursorMode == GLFW_CURSOR_NORMAL ||
window->cursorMode == GLFW_CURSOR_CAPTURED)
{
if (window->cursor)
{
@ -492,6 +475,25 @@ static void updateCursorImage(_GLFWwindow* window)
}
}
// Grabs the cursor and confines it to the window
//
static void captureCursor(_GLFWwindow* window)
{
XGrabPointer(_glfw.x11.display, window->x11.handle, True,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync,
window->x11.handle,
None,
CurrentTime);
}
// Ungrabs the cursor
//
static void releaseCursor(void)
{
XUngrabPointer(_glfw.x11.display, CurrentTime);
}
// Enable XI2 raw mouse motion events
//
static void enableRawMouseMotion(_GLFWwindow* window)
@ -534,12 +536,7 @@ static void disableCursor(_GLFWwindow* window)
&_glfw.x11.restoreCursorPosY);
updateCursorImage(window);
_glfwCenterCursorInContentArea(window);
XGrabPointer(_glfw.x11.display, window->x11.handle, True,
ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
GrabModeAsync, GrabModeAsync,
window->x11.handle,
_glfw.x11.hiddenCursorHandle,
CurrentTime);
captureCursor(window);
}
// Exit disabled cursor mode for the specified window
@ -550,7 +547,7 @@ static void enableCursor(_GLFWwindow* window)
disableRawMouseMotion(window);
_glfw.x11.disabledCursorWindow = NULL;
XUngrabPointer(_glfw.x11.display, CurrentTime);
releaseCursor();
_glfwSetCursorPosX11(window,
_glfw.x11.restoreCursorPosX,
_glfw.x11.restoreCursorPosY);
@ -580,6 +577,14 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
height *= _glfw.x11.contentScaleY;
}
int xpos = 0, ypos = 0;
if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION)
{
xpos = wndconfig->xpos;
ypos = wndconfig->ypos;
}
// Create a colormap based on the visual used by the current context
window->x11.colormap = XCreateColormap(_glfw.x11.display,
_glfw.x11.root,
@ -600,7 +605,7 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
window->x11.parent = _glfw.x11.root;
window->x11.handle = XCreateWindow(_glfw.x11.display,
_glfw.x11.root,
0, 0, // Position
xpos, ypos,
width, height,
0, // Border width
depth, // Color depth
@ -703,7 +708,37 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
XFree(hints);
}
updateNormalHints(window, width, height);
// Set ICCCM WM_NORMAL_HINTS property
{
XSizeHints* hints = XAllocSizeHints();
if (!hints)
{
_glfwInputError(GLFW_OUT_OF_MEMORY, "X11: Failed to allocate size hints");
return GLFW_FALSE;
}
if (!wndconfig->resizable)
{
hints->flags |= (PMinSize | PMaxSize);
hints->min_width = hints->max_width = width;
hints->min_height = hints->max_height = height;
}
// HACK: Explicitly setting PPosition to any value causes some WMs, notably
// Compiz and Metacity, to honor the position of unmapped windows
if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION)
{
hints->flags |= PPosition;
hints->x = 0;
hints->y = 0;
}
hints->flags |= PWinGravity;
hints->win_gravity = StaticGravity;
XSetWMNormalHints(_glfw.x11.display, window->x11.handle, hints);
XFree(hints);
}
// Set ICCCM WM_CLASS property
{
@ -887,20 +922,6 @@ static Atom writeTargetToProperty(const XSelectionRequestEvent* request)
return None;
}
static void handleSelectionClear(XEvent* event)
{
if (event->xselectionclear.selection == _glfw.x11.PRIMARY)
{
_glfw_free(_glfw.x11.primarySelectionString);
_glfw.x11.primarySelectionString = NULL;
}
else
{
_glfw_free(_glfw.x11.clipboardString);
_glfw.x11.clipboardString = NULL;
}
}
static void handleSelectionRequest(XEvent* event)
{
const XSelectionRequestEvent* request = &event->xselectionrequest;
@ -958,7 +979,7 @@ static const char* getSelectionString(Atom selection)
SelectionNotify,
&notification))
{
waitForEvent(NULL);
waitForX11Event(NULL);
}
if (notification.xselection.property == None)
@ -994,7 +1015,7 @@ static const char* getSelectionString(Atom selection)
isSelPropNewValueNotify,
(XPointer) &notification))
{
waitForEvent(NULL);
waitForX11Event(NULL);
}
XFree(data);
@ -1021,13 +1042,16 @@ static const char* getSelectionString(Atom selection)
if (!itemCount)
{
if (targets[i] == XA_STRING)
if (string)
{
*selectionString = convertLatin1toUTF8(string);
_glfw_free(string);
if (targets[i] == XA_STRING)
{
*selectionString = convertLatin1toUTF8(string);
_glfw_free(string);
}
else
*selectionString = string;
}
else
*selectionString = string;
break;
}
@ -1193,12 +1217,7 @@ static void processEvent(XEvent *event)
return;
}
if (event->type == SelectionClear)
{
handleSelectionClear(event);
return;
}
else if (event->type == SelectionRequest)
if (event->type == SelectionRequest)
{
handleSelectionRequest(event);
return;
@ -1238,7 +1257,7 @@ static void processEvent(XEvent *event)
// (the server never sends a timestamp of zero)
// NOTE: Timestamp difference is compared to handle wrap-around
Time diff = event->xkey.time - window->x11.keyPressTimes[keycode];
if (diff == event->xkey.time || (diff > 0 && diff < (1 << 31)))
if (diff == event->xkey.time || (diff > 0 && diff < ((Time)1 << 31)))
{
if (keycode)
_glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
@ -1686,7 +1705,7 @@ static void processEvent(XEvent *event)
if (result)
{
int count;
char** paths = parseUriList(data, &count);
char** paths = _glfwParseUriList(data, &count);
_glfwInputDrop(window, count, (const char**) paths);
@ -1729,6 +1748,8 @@ static void processEvent(XEvent *event)
if (window->cursorMode == GLFW_CURSOR_DISABLED)
disableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
if (window->x11.ic)
XSetICFocus(window->x11.ic);
@ -1749,6 +1770,8 @@ static void processEvent(XEvent *event)
if (window->cursorMode == GLFW_CURSOR_DISABLED)
enableCursor(window);
else if (window->cursorMode == GLFW_CURSOR_CAPTURED)
releaseCursor();
if (window->x11.ic)
XUnsetICFocus(window->x11.ic);
@ -1875,10 +1898,6 @@ void _glfwPushSelectionToManagerX11(void)
handleSelectionRequest(&event);
break;
case SelectionClear:
handleSelectionClear(&event);
break;
case SelectionNotify:
{
if (event.xselection.target == _glfw.x11.SAVE_TARGETS)
@ -1896,7 +1915,7 @@ void _glfwPushSelectionToManagerX11(void)
}
}
waitForEvent(NULL);
waitForX11Event(NULL);
}
}
@ -1937,10 +1956,10 @@ void _glfwCreateInputContextX11(_GLFWwindow* window)
////// GLFW platform API //////
//////////////////////////////////////////////////////////////////////////
int _glfwCreateWindowX11(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
GLFWbool _glfwCreateWindowX11(_GLFWwindow* window,
const _GLFWwndconfig* wndconfig,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig)
{
Visual* visual = NULL;
int depth;
@ -1994,13 +2013,31 @@ int _glfwCreateWindowX11(_GLFWwindow* window,
if (!_glfwCreateContextOSMesa(window, ctxconfig, fbconfig))
return GLFW_FALSE;
}
if (!_glfwRefreshContextAttribs(window, ctxconfig))
return GLFW_FALSE;
}
if (wndconfig->mousePassthrough)
_glfwSetWindowMousePassthroughX11(window, GLFW_TRUE);
if (window->monitor)
{
_glfwShowWindowX11(window);
updateWindowMode(window);
acquireMonitor(window);
if (wndconfig->centerCursor)
_glfwCenterCursorInContentArea(window);
}
else
{
if (wndconfig->visible)
{
_glfwShowWindowX11(window);
if (wndconfig->focused)
_glfwFocusWindowX11(window);
}
}
XFlush(_glfw.x11.display);
@ -2010,7 +2047,7 @@ int _glfwCreateWindowX11(_GLFWwindow* window,
void _glfwDestroyWindowX11(_GLFWwindow* window)
{
if (_glfw.x11.disabledCursorWindow == window)
_glfw.x11.disabledCursorWindow = NULL;
enableCursor(window);
if (window->monitor)
releaseMonitor(window);
@ -2238,7 +2275,7 @@ void _glfwGetWindowFrameSizeX11(_GLFWwindow* window,
isFrameExtentsEvent,
(XPointer) window))
{
if (!waitForEvent(&timeout))
if (!waitForX11Event(&timeout))
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue");
@ -2486,7 +2523,7 @@ void _glfwSetWindowMonitorX11(_GLFWwindow* window,
XFlush(_glfw.x11.display);
}
int _glfwWindowFocusedX11(_GLFWwindow* window)
GLFWbool _glfwWindowFocusedX11(_GLFWwindow* window)
{
Window focused;
int state;
@ -2495,19 +2532,19 @@ int _glfwWindowFocusedX11(_GLFWwindow* window)
return window->x11.handle == focused;
}
int _glfwWindowIconifiedX11(_GLFWwindow* window)
GLFWbool _glfwWindowIconifiedX11(_GLFWwindow* window)
{
return getWindowState(window) == IconicState;
}
int _glfwWindowVisibleX11(_GLFWwindow* window)
GLFWbool _glfwWindowVisibleX11(_GLFWwindow* window)
{
XWindowAttributes wa;
XGetWindowAttributes(_glfw.x11.display, window->x11.handle, &wa);
return wa.map_state == IsViewable;
}
int _glfwWindowMaximizedX11(_GLFWwindow* window)
GLFWbool _glfwWindowMaximizedX11(_GLFWwindow* window)
{
Atom* states;
GLFWbool maximized = GLFW_FALSE;
@ -2541,7 +2578,7 @@ int _glfwWindowMaximizedX11(_GLFWwindow* window)
return maximized;
}
int _glfwWindowHoveredX11(_GLFWwindow* window)
GLFWbool _glfwWindowHoveredX11(_GLFWwindow* window)
{
Window w = _glfw.x11.root;
while (w)
@ -2569,7 +2606,7 @@ int _glfwWindowHoveredX11(_GLFWwindow* window)
return GLFW_FALSE;
}
int _glfwFramebufferTransparentX11(_GLFWwindow* window)
GLFWbool _glfwFramebufferTransparentX11(_GLFWwindow* window)
{
if (!window->x11.transparent)
return GLFW_FALSE;
@ -2744,9 +2781,9 @@ GLFWbool _glfwRawMouseMotionSupportedX11(void)
void _glfwPollEventsX11(void)
{
_GLFWwindow* window;
drainEmptyEvents();
#if defined(__linux__)
#if defined(GLFW_BUILD_LINUX_JOYSTICK)
if (_glfw.joysticksInitialized)
_glfwDetectJoystickConnectionLinux();
#endif
@ -2759,7 +2796,7 @@ void _glfwPollEventsX11(void)
processEvent(&event);
}
window = _glfw.x11.disabledCursorWindow;
_GLFWwindow* window = _glfw.x11.disabledCursorWindow;
if (window)
{
int width, height;
@ -2779,32 +2816,19 @@ void _glfwPollEventsX11(void)
void _glfwWaitEventsX11(void)
{
while (!XPending(_glfw.x11.display))
waitForEvent(NULL);
waitForAnyEvent(NULL);
_glfwPollEventsX11();
}
void _glfwWaitEventsTimeoutX11(double timeout)
{
while (!XPending(_glfw.x11.display))
{
if (!waitForEvent(&timeout))
break;
}
waitForAnyEvent(&timeout);
_glfwPollEventsX11();
}
void _glfwPostEmptyEventX11(void)
{
XEvent event = { ClientMessage };
event.xclient.window = _glfw.x11.helperWindowHandle;
event.xclient.format = 32; // Data is 32-bit longs
event.xclient.message_type = _glfw.x11.NULL_;
XSendEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, False, 0, &event);
XFlush(_glfw.x11.display);
writeEmptyEvent();
}
void _glfwGetCursorPosX11(_GLFWwindow* window, double* xpos, double* ypos)
@ -2837,16 +2861,40 @@ void _glfwSetCursorPosX11(_GLFWwindow* window, double x, double y)
void _glfwSetCursorModeX11(_GLFWwindow* window, int mode)
{
if (mode == GLFW_CURSOR_DISABLED)
if (_glfwWindowFocusedX11(window))
{
if (_glfwWindowFocusedX11(window))
disableCursor(window);
}
else if (_glfw.x11.disabledCursorWindow == window)
enableCursor(window);
else
updateCursorImage(window);
if (mode == GLFW_CURSOR_DISABLED)
{
_glfwGetCursorPosX11(window,
&_glfw.x11.restoreCursorPosX,
&_glfw.x11.restoreCursorPosY);
_glfwCenterCursorInContentArea(window);
if (window->rawMouseMotion)
enableRawMouseMotion(window);
}
else if (_glfw.x11.disabledCursorWindow == window)
{
if (window->rawMouseMotion)
disableRawMouseMotion(window);
}
if (mode == GLFW_CURSOR_DISABLED || mode == GLFW_CURSOR_CAPTURED)
captureCursor(window);
else
releaseCursor();
if (mode == GLFW_CURSOR_DISABLED)
_glfw.x11.disabledCursorWindow = window;
else if (_glfw.x11.disabledCursorWindow == window)
{
_glfw.x11.disabledCursorWindow = NULL;
_glfwSetCursorPosX11(window,
_glfw.x11.restoreCursorPosX,
_glfw.x11.restoreCursorPosY);
}
}
updateCursorImage(window);
XFlush(_glfw.x11.display);
}
@ -2885,9 +2933,9 @@ int _glfwGetKeyScancodeX11(int key)
return _glfw.x11.scancodes[key];
}
int _glfwCreateCursorX11(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
GLFWbool _glfwCreateCursorX11(_GLFWcursor* cursor,
const GLFWimage* image,
int xhot, int yhot)
{
cursor->x11.handle = _glfwCreateNativeCursorX11(image, xhot, yhot);
if (!cursor->x11.handle)
@ -2896,7 +2944,7 @@ int _glfwCreateCursorX11(_GLFWcursor* cursor,
return GLFW_TRUE;
}
int _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape)
GLFWbool _glfwCreateStandardCursorX11(_GLFWcursor* cursor, int shape)
{
if (_glfw.x11.xcursor.handle)
{
@ -3002,7 +3050,8 @@ void _glfwDestroyCursorX11(_GLFWcursor* cursor)
void _glfwSetCursorX11(_GLFWwindow* window, _GLFWcursor* cursor)
{
if (window->cursorMode == GLFW_CURSOR_NORMAL)
if (window->cursorMode == GLFW_CURSOR_NORMAL ||
window->cursorMode == GLFW_CURSOR_CAPTURED)
{
updateCursorImage(window);
XFlush(_glfw.x11.display);
@ -3103,9 +3152,9 @@ void _glfwGetRequiredInstanceExtensionsX11(char** extensions)
extensions[1] = "VK_KHR_xlib_surface";
}
int _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
GLFWbool _glfwGetPhysicalDevicePresentationSupportX11(VkInstance instance,
VkPhysicalDevice device,
uint32_t queuefamily)
{
VisualID visualID = XVisualIDFromVisual(DefaultVisual(_glfw.x11.display,
_glfw.x11.screen));
@ -3302,3 +3351,5 @@ GLFWAPI const char* glfwGetX11SelectionString(void)
return getSelectionString(_glfw.x11.PRIMARY);
}
#endif // _GLFW_X11

View File

@ -29,6 +29,7 @@
#include "internal.h"
#if defined(_GLFW_X11) || defined(_GLFW_WAYLAND)
/*
* Marcus: This code was originally written by Markus G. Kuhn.
@ -940,3 +941,5 @@ uint32_t _glfwKeySym2Unicode(unsigned int keysym)
return GLFW_INVALID_CODEPOINT;
}
#endif // _GLFW_WAYLAND or _GLFW_X11