mirror of https://github.com/xemu-project/xemu.git
Merge branch 'master' into LightGun
This commit is contained in:
commit
e67bd8115a
|
@ -79,7 +79,7 @@ jobs:
|
|||
artifact_name: xemu-win-aarch64-release
|
||||
arch: aarch64
|
||||
env:
|
||||
DOCKER_IMAGE_NAME: ghcr.io/xemu-project/xemu-win64-toolchain:sha-03e3cd0
|
||||
DOCKER_IMAGE_NAME: ghcr.io/xemu-project/xemu-win64-toolchain:sha-3bdb9e7
|
||||
|
||||
steps:
|
||||
- name: Download source package
|
||||
|
@ -180,7 +180,7 @@ jobs:
|
|||
build_param:
|
||||
artifact_name: xemu-ubuntu-x86_64-release
|
||||
artifact_filename: xemu-ubuntu-x86_64-release.tgz
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
- arch: aarch64
|
||||
configuration: Debug
|
||||
build_param: --debug
|
||||
|
@ -213,7 +213,7 @@ jobs:
|
|||
run: |
|
||||
pushd src
|
||||
echo -e "\
|
||||
xemu (1:$(cat XEMU_VERSION)-0) unstable; urgency=medium\n\
|
||||
xemu (1:0.0.0-0) unstable; urgency=medium\n\
|
||||
Built from $(cat XEMU_VERSION)\n\
|
||||
-- Matt Borgerson <contact@mborgerson.com> $(date -R)" > debian/changelog
|
||||
popd
|
||||
|
@ -229,7 +229,7 @@ jobs:
|
|||
export CCACHE_DIR=/tmp/xemu-ccache
|
||||
export CCACHE_MAXSIZE=512M
|
||||
export PATH="/usr/lib/ccache:$PATH"
|
||||
export XEMU_BUILD_OPTIONS="${{ matrix.build_param }} --extra-cflags='-fuse-ld=gold'"
|
||||
export XEMU_BUILD_OPTIONS="${{ matrix.build_param }}"
|
||||
ccache -z
|
||||
|
||||
# XXX: dpkg-genbuildinfo takes two minutes on GH runners. Nuke it for now.
|
||||
|
|
4
build.sh
4
build.sh
|
@ -36,7 +36,6 @@ package_macos() {
|
|||
dylibbundler -cd -of -b -x dist/xemu.app/Contents/MacOS/xemu \
|
||||
-d ${lib_path}/ \
|
||||
-p "@executable_path/${lib_rpath}/" \
|
||||
-s ${PWD}/macos-libs/${target_arch}/opt/local/libexec/openssl11/lib/ \
|
||||
-s ${PWD}/macos-libs/${target_arch}/opt/local/lib/
|
||||
|
||||
# Fixup some paths dylibbundler missed
|
||||
|
@ -226,8 +225,7 @@ case "$platform" in # Adjust compilation options based on platform
|
|||
sys_cflags='-march=ivybridge'
|
||||
fi
|
||||
sys_ldflags='-headerpad_max_install_names'
|
||||
export PKG_CONFIG_PATH="${lib_prefix}/lib/pkgconfig"
|
||||
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:${lib_prefix}/libexec/openssl11/lib/pkgconfig"
|
||||
export PKG_CONFIG_LIBDIR="${lib_prefix}/lib/pkgconfig"
|
||||
opts="$opts --disable-cocoa --cross-prefix="
|
||||
postbuild='package_macos'
|
||||
;;
|
||||
|
|
Binary file not shown.
|
@ -8,7 +8,7 @@ pfiles = [
|
|||
'abxy.ttf',
|
||||
'Roboto-Medium.ttf',
|
||||
'RobotoCondensed-Regular.ttf',
|
||||
'font_awesome_6_1_1_solid.otf',
|
||||
'font_awesome_6_1_1_solid.min.otf', # Update glyphs with scripts/gen-min-fa-font.sh
|
||||
]
|
||||
|
||||
libpfile_targets = []
|
||||
|
|
|
@ -18,6 +18,7 @@ Build-Depends: debhelper (>= 11),
|
|||
libpcap-dev,
|
||||
libslirp-dev,
|
||||
libvulkan-dev,
|
||||
libcurl4-gnutls-dev,
|
||||
Standards-Version: 3.9.8
|
||||
Homepage: https://xemu.app
|
||||
XS-Debian-Vcs-Browser: https://github.com/mborgerson/xemu
|
||||
|
|
|
@ -203,10 +203,6 @@ void pgraph_gl_draw_begin(NV2AState *d)
|
|||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
/* Clipping */
|
||||
glEnable(GL_CLIP_DISTANCE0);
|
||||
glEnable(GL_CLIP_DISTANCE1);
|
||||
|
||||
/* Front-face select */
|
||||
glFrontFace(pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER)
|
||||
& NV_PGRAPH_SETUPRASTER_FRONTFACE
|
||||
|
@ -240,6 +236,8 @@ void pgraph_gl_draw_begin(NV2AState *d)
|
|||
GLfloat zfactor = *(float*)&zfactor_u32;
|
||||
uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS);
|
||||
GLfloat zbias = *(float*)&zbias_u32;
|
||||
// FIXME: with Linux and Mesa, zbias must be multiplied by 0.5 in
|
||||
// order to have the same depth value offset as Xbox.
|
||||
glPolygonOffset(zfactor, zbias);
|
||||
}
|
||||
|
||||
|
@ -255,13 +253,7 @@ void pgraph_gl_draw_begin(NV2AState *d)
|
|||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
if (GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_ZCOMPRESSOCCLUDE),
|
||||
NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN) ==
|
||||
NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN_CLAMP) {
|
||||
glEnable(GL_DEPTH_CLAMP);
|
||||
} else {
|
||||
glDisable(GL_DEPTH_CLAMP);
|
||||
}
|
||||
glEnable(GL_DEPTH_CLAMP);
|
||||
|
||||
if (GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
|
||||
NV_PGRAPH_CONTROL_3_SHADEMODE) ==
|
||||
|
|
|
@ -106,6 +106,7 @@ typedef struct ShaderBinding {
|
|||
|
||||
GLint surface_size_loc;
|
||||
GLint clip_range_loc;
|
||||
GLint depth_offset_loc;
|
||||
|
||||
GLint vsh_constant_loc[NV2A_VERTEXSHADER_CONSTANTS];
|
||||
uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4];
|
||||
|
|
|
@ -154,6 +154,7 @@ static void update_shader_constant_locations(ShaderBinding *binding)
|
|||
}
|
||||
binding->surface_size_loc = glGetUniformLocation(binding->gl_program, "surfaceSize");
|
||||
binding->clip_range_loc = glGetUniformLocation(binding->gl_program, "clipRange");
|
||||
binding->depth_offset_loc = glGetUniformLocation(binding->gl_program, "depthOffset");
|
||||
binding->fog_color_loc = glGetUniformLocation(binding->gl_program, "fogColor");
|
||||
binding->fog_param_loc = glGetUniformLocation(binding->gl_program, "fogParam");
|
||||
|
||||
|
@ -712,9 +713,9 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
|
|||
}
|
||||
}
|
||||
if (binding->alpha_ref_loc != -1) {
|
||||
float alpha_ref = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0),
|
||||
NV_PGRAPH_CONTROL_0_ALPHAREF) / 255.0;
|
||||
glUniform1f(binding->alpha_ref_loc, alpha_ref);
|
||||
int alpha_ref = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0),
|
||||
NV_PGRAPH_CONTROL_0_ALPHAREF);
|
||||
glUniform1i(binding->alpha_ref_loc, alpha_ref);
|
||||
}
|
||||
|
||||
|
||||
|
@ -886,11 +887,36 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
|
|||
uint32_t v[2];
|
||||
v[0] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMIN);
|
||||
v[1] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMAX);
|
||||
float zclip_min = *(float*)&v[0] / zmax * 2.0 - 1.0;
|
||||
float zclip_max = *(float*)&v[1] / zmax * 2.0 - 1.0;
|
||||
float zclip_min = *(float *)&v[0];
|
||||
float zclip_max = *(float *)&v[1];
|
||||
glUniform4f(binding->clip_range_loc, 0, zmax, zclip_min, zclip_max);
|
||||
}
|
||||
|
||||
if (binding->depth_offset_loc != -1) {
|
||||
float zbias = 0.0f;
|
||||
|
||||
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
|
||||
(NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) {
|
||||
uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS);
|
||||
zbias = *(float *)&zbias_u32;
|
||||
|
||||
if (pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR) != 0 &&
|
||||
(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
|
||||
NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE)) {
|
||||
/* TODO: emulate zfactor when z_perspective true, i.e.
|
||||
* w-buffering. Perhaps calculate an additional offset based on
|
||||
* triangle orientation in geometry shader and pass the result
|
||||
* to fragment shader and add it to gl_FragDepth as well.
|
||||
*/
|
||||
NV2A_UNIMPLEMENTED("NV_PGRAPH_ZOFFSETFACTOR for w-buffering");
|
||||
}
|
||||
}
|
||||
|
||||
glUniform1f(binding->depth_offset_loc, zbias);
|
||||
}
|
||||
|
||||
/* Clipping regions */
|
||||
unsigned int max_gl_width = pg->surface_binding_dim.width;
|
||||
unsigned int max_gl_height = pg->surface_binding_dim.height;
|
||||
|
@ -956,6 +982,7 @@ static bool test_shaders_dirty(PGRAPHState *pg)
|
|||
CR_1(NV_PGRAPH_CSV1_B) \
|
||||
CR_1(NV_PGRAPH_SETUPRASTER) \
|
||||
CR_1(NV_PGRAPH_SHADERPROG) \
|
||||
CR_1(NV_PGRAPH_ZCOMPRESSOCCLUDE) \
|
||||
CR_8(NV_PGRAPH_COMBINECOLORI0) \
|
||||
CR_8(NV_PGRAPH_COMBINECOLORO0) \
|
||||
CR_8(NV_PGRAPH_COMBINEALPHAI0) \
|
||||
|
|
|
@ -23,34 +23,32 @@
|
|||
|
||||
MString *pgraph_get_glsl_vtx_header(MString *out, bool location, bool smooth, bool in, bool prefix, bool array)
|
||||
{
|
||||
const char *flat_s = "flat";
|
||||
const char *noperspective_s = "noperspective";
|
||||
const char *qualifier_s = smooth ? noperspective_s : flat_s;
|
||||
const char *qualifiers[11] = {
|
||||
noperspective_s, flat_s, qualifier_s, qualifier_s,
|
||||
qualifier_s, qualifier_s, noperspective_s, noperspective_s,
|
||||
noperspective_s, noperspective_s, noperspective_s
|
||||
};
|
||||
const char *flat_s = "flat ";
|
||||
const char *smooth_s = "";
|
||||
const char *qualifier_s = smooth ? smooth_s : flat_s;
|
||||
const char *qualifiers[9] = { qualifier_s, qualifier_s, qualifier_s,
|
||||
qualifier_s, smooth_s, smooth_s,
|
||||
smooth_s, smooth_s, smooth_s };
|
||||
|
||||
const char *in_out_s = in ? "in" : "out";
|
||||
|
||||
const char *float_s = "float";
|
||||
const char *vec4_s = "vec4";
|
||||
const char *types[11] = { float_s, float_s, vec4_s, vec4_s, vec4_s, vec4_s,
|
||||
float_s, vec4_s, vec4_s, vec4_s, vec4_s };
|
||||
const char *types[9] = { vec4_s, vec4_s, vec4_s, vec4_s, float_s,
|
||||
vec4_s, vec4_s, vec4_s, vec4_s };
|
||||
|
||||
const char *prefix_s = prefix ? "v_" : "";
|
||||
const char *names[11] = {
|
||||
"vtx_inv_w", "vtx_inv_w_flat", "vtxD0", "vtxD1", "vtxB0", "vtxB1",
|
||||
"vtxFog", "vtxT0", "vtxT1", "vtxT2", "vtxT3",
|
||||
const char *names[9] = {
|
||||
"vtxD0", "vtxD1", "vtxB0", "vtxB1", "vtxFog",
|
||||
"vtxT0", "vtxT1", "vtxT2", "vtxT3",
|
||||
};
|
||||
const char *suffix_s = array ? "[]" : "";
|
||||
|
||||
for (int i = 0; i < 11; i++) {
|
||||
for (int i = 0; i < 9; i++) {
|
||||
if (location) {
|
||||
mstring_append_fmt(out, "layout(location = %d) ", i);
|
||||
}
|
||||
mstring_append_fmt(out, "%s %s %s %s%s%s;\n",
|
||||
mstring_append_fmt(out, "%s%s %s %s%s%s;\n",
|
||||
qualifiers[i], in_out_s, types[i], prefix_s, names[i], suffix_s);
|
||||
}
|
||||
|
||||
|
|
|
@ -182,10 +182,6 @@ MString *pgraph_gen_geom_glsl(enum ShaderPolygonMode polygon_front_mode,
|
|||
"void emit_vertex(int index, int _unused) {\n"
|
||||
" gl_Position = gl_in[index].gl_Position;\n"
|
||||
" gl_PointSize = gl_in[index].gl_PointSize;\n"
|
||||
// " gl_ClipDistance[0] = gl_in[index].gl_ClipDistance[0];\n"
|
||||
// " gl_ClipDistance[1] = gl_in[index].gl_ClipDistance[1];\n"
|
||||
" vtx_inv_w = v_vtx_inv_w[index];\n"
|
||||
" vtx_inv_w_flat = v_vtx_inv_w[index];\n"
|
||||
" vtxD0 = v_vtxD0[index];\n"
|
||||
" vtxD1 = v_vtxD1[index];\n"
|
||||
" vtxB0 = v_vtxB0[index];\n"
|
||||
|
@ -202,10 +198,6 @@ MString *pgraph_gen_geom_glsl(enum ShaderPolygonMode polygon_front_mode,
|
|||
"void emit_vertex(int index, int provoking_index) {\n"
|
||||
" gl_Position = gl_in[index].gl_Position;\n"
|
||||
" gl_PointSize = gl_in[index].gl_PointSize;\n"
|
||||
// " gl_ClipDistance[0] = gl_in[index].gl_ClipDistance[0];\n"
|
||||
// " gl_ClipDistance[1] = gl_in[index].gl_ClipDistance[1];\n"
|
||||
" vtx_inv_w = v_vtx_inv_w[index];\n"
|
||||
" vtx_inv_w_flat = v_vtx_inv_w[provoking_index];\n"
|
||||
" vtxD0 = v_vtxD0[provoking_index];\n"
|
||||
" vtxD1 = v_vtxD1[provoking_index];\n"
|
||||
" vtxB0 = v_vtxB0[provoking_index];\n"
|
||||
|
|
|
@ -743,10 +743,12 @@ static MString* psh_convert(struct PixelShader *ps)
|
|||
"layout(location = 0) out vec4 fragColor;\n");
|
||||
}
|
||||
|
||||
mstring_append_fmt(preflight, "%sfloat alphaRef;\n"
|
||||
mstring_append_fmt(preflight, "%sint alphaRef;\n"
|
||||
"%svec4 fogColor;\n"
|
||||
"%sivec4 clipRegion[8];\n",
|
||||
u, u, u);
|
||||
"%sivec4 clipRegion[8];\n"
|
||||
"%svec4 clipRange;\n"
|
||||
"%sfloat depthOffset;\n",
|
||||
u, u, u, u, u);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mstring_append_fmt(preflight, "%smat2 bumpMat%d;\n"
|
||||
"%sfloat bumpScale%d;\n"
|
||||
|
@ -861,28 +863,62 @@ static MString* psh_convert(struct PixelShader *ps)
|
|||
"}\n");
|
||||
}
|
||||
|
||||
/* calculate perspective-correct inputs */
|
||||
MString *vars = mstring_new();
|
||||
if (ps->state.smooth_shading) {
|
||||
mstring_append(vars, "vec4 pD0 = vtxD0 / vtx_inv_w;\n");
|
||||
mstring_append(vars, "vec4 pD1 = vtxD1 / vtx_inv_w;\n");
|
||||
mstring_append(vars, "vec4 pB0 = vtxB0 / vtx_inv_w;\n");
|
||||
mstring_append(vars, "vec4 pB1 = vtxB1 / vtx_inv_w;\n");
|
||||
} else {
|
||||
mstring_append(vars, "vec4 pD0 = vtxD0 / vtx_inv_w_flat;\n");
|
||||
mstring_append(vars, "vec4 pD1 = vtxD1 / vtx_inv_w_flat;\n");
|
||||
mstring_append(vars, "vec4 pB0 = vtxB0 / vtx_inv_w_flat;\n");
|
||||
mstring_append(vars, "vec4 pB1 = vtxB1 / vtx_inv_w_flat;\n");
|
||||
/* Depth clipping */
|
||||
if (ps->state.depth_clipping) {
|
||||
if (ps->state.z_perspective) {
|
||||
mstring_append(
|
||||
clip, "float zvalue = 1.0/gl_FragCoord.w + depthOffset;\n"
|
||||
"if (zvalue < clipRange.z || clipRange.w < zvalue) {\n"
|
||||
" discard;\n"
|
||||
"}\n");
|
||||
} else {
|
||||
/* Take care of floating point precision problems. MS dashboard
|
||||
* outputs exactly 0.0 z-coordinates and then our fixed function
|
||||
* vertex shader outputs -w as the z-coordinate when OpenGL is
|
||||
* used. Since -w/w = -1, this should give us exactly 0.0 as
|
||||
* gl_FragCoord.z here. Unfortunately, with AMD Radeon RX 6600 the
|
||||
* result is slightly greater than 0. MS dashboard sets the clip
|
||||
* range to [0.0, 0.0] and so the imprecision causes unwanted
|
||||
* clipping. Note that since Vulkan uses NDC range [0,1] it
|
||||
* doesn't suffer from this problem with Radeon. Also, despite the
|
||||
* imprecision OpenGL Radeon writes the correct value 0 to the depth
|
||||
* buffer (if writing is enabled.) Radeon appears to write floored
|
||||
* values. To compare, Intel integrated UHD 770 has gl_FragCoord.z
|
||||
* exactly 0 (and writes rounded to closest integer values to the
|
||||
* depth buffer.) Radeon OpenGL problem could also be fixed by using
|
||||
* glClipControl(), but it requires OpenGL 4.5.
|
||||
* Above is based on experiments with Linux and Mesa.
|
||||
*/
|
||||
if (ps->state.vulkan) {
|
||||
mstring_append(
|
||||
clip, "if (gl_FragCoord.z*clipRange.y < clipRange.z ||\n"
|
||||
" gl_FragCoord.z*clipRange.y > clipRange.w) {\n"
|
||||
" discard;\n"
|
||||
"}\n");
|
||||
} else {
|
||||
mstring_append(
|
||||
clip, "if ((gl_FragCoord.z + 1.0f/16777216.0f)*clipRange.y < clipRange.z ||\n"
|
||||
" (gl_FragCoord.z - 1.0f/16777216.0f)*clipRange.y > clipRange.w) {\n"
|
||||
" discard;\n"
|
||||
"}\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
mstring_append(vars, "vec4 pFog = vec4(fogColor.rgb, clamp(vtxFog / vtx_inv_w, 0.0, 1.0));\n");
|
||||
mstring_append(vars, "vec4 pT0 = vtxT0 / vtx_inv_w;\n");
|
||||
mstring_append(vars, "vec4 pT1 = vtxT1 / vtx_inv_w;\n");
|
||||
mstring_append(vars, "vec4 pT2 = vtxT2 / vtx_inv_w;\n");
|
||||
|
||||
MString *vars = mstring_new();
|
||||
mstring_append(vars, "vec4 pD0 = vtxD0;\n");
|
||||
mstring_append(vars, "vec4 pD1 = vtxD1;\n");
|
||||
mstring_append(vars, "vec4 pB0 = vtxB0;\n");
|
||||
mstring_append(vars, "vec4 pB1 = vtxB1;\n");
|
||||
mstring_append(vars, "vec4 pFog = vec4(fogColor.rgb, clamp(vtxFog, 0.0, 1.0));\n");
|
||||
mstring_append(vars, "vec4 pT0 = vtxT0;\n");
|
||||
mstring_append(vars, "vec4 pT1 = vtxT1;\n");
|
||||
mstring_append(vars, "vec4 pT2 = vtxT2;\n");
|
||||
if (ps->state.point_sprite) {
|
||||
assert(!ps->state.rect_tex[3]);
|
||||
mstring_append(vars, "vec4 pT3 = vec4(gl_PointCoord, 1.0, 1.0);\n");
|
||||
} else {
|
||||
mstring_append(vars, "vec4 pT3 = vtxT3 / vtx_inv_w;\n");
|
||||
mstring_append(vars, "vec4 pT3 = vtxT3;\n");
|
||||
}
|
||||
mstring_append(vars, "\n");
|
||||
mstring_append(vars, "vec4 v0 = pD0;\n");
|
||||
|
@ -1190,7 +1226,9 @@ static MString* psh_convert(struct PixelShader *ps)
|
|||
assert(false);
|
||||
break;
|
||||
}
|
||||
mstring_append_fmt(ps->code, "if (!(fragColor.a %s alphaRef)) discard;\n",
|
||||
mstring_append_fmt(ps->code,
|
||||
"int fragAlpha = int(round(fragColor.a * 255.0));\n"
|
||||
"if (!(fragAlpha %s alphaRef)) discard;\n",
|
||||
alpha_op);
|
||||
}
|
||||
}
|
||||
|
@ -1206,6 +1244,23 @@ static MString* psh_convert(struct PixelShader *ps)
|
|||
}
|
||||
}
|
||||
|
||||
if (ps->state.z_perspective) {
|
||||
if (!ps->state.depth_clipping) {
|
||||
mstring_append(ps->code,
|
||||
"float zvalue = 1.0/gl_FragCoord.w + depthOffset;\n");
|
||||
}
|
||||
/* TODO: With integer depth buffers Xbox hardware floors values and so
|
||||
* does Radeon, but Intel UHD 770 rounds to nearest. Should probably
|
||||
* floor here explicitly (in some way that doesn't also cause
|
||||
* imprecision issues due to division by clipRange.y)
|
||||
*/
|
||||
mstring_append(ps->code,
|
||||
"gl_FragDepth = clamp(zvalue, clipRange.z, clipRange.w)/clipRange.y;\n");
|
||||
} else if (!ps->state.depth_clipping) {
|
||||
mstring_append(ps->code,
|
||||
"gl_FragDepth = clamp(gl_FragCoord.z, clipRange.z/clipRange.y, clipRange.w/clipRange.y);\n");
|
||||
}
|
||||
|
||||
MString *final = mstring_new();
|
||||
mstring_append_fmt(final, "#version %d\n\n", ps->state.vulkan ? 450 : 400);
|
||||
mstring_append(final, mstring_get_str(preflight));
|
||||
|
|
|
@ -421,13 +421,13 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
}
|
||||
|
||||
mstring_append(body,
|
||||
" oPos = invViewport * (tPosition * compositeMat);\n"
|
||||
" oPos = tPosition * compositeMat;\n"
|
||||
" oPos.w = clampAwayZeroInf(oPos.w);\n"
|
||||
" oPos = invViewport * oPos;\n"
|
||||
);
|
||||
|
||||
if (state->vulkan) {
|
||||
mstring_append(body, " oPos.y *= -1;\n");
|
||||
} else {
|
||||
mstring_append(body, " oPos.z = oPos.z * 2.0 - oPos.w;\n");
|
||||
}
|
||||
|
||||
/* FIXME: Testing */
|
||||
|
@ -445,14 +445,6 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
|
|||
mstring_append_fmt(body, " oPts.x = %f * %d;\n", state->point_size,
|
||||
state->surface_scale_factor);
|
||||
}
|
||||
|
||||
mstring_append(body,
|
||||
" if (oPos.w == 0.0 || isinf(oPos.w)) {\n"
|
||||
" vtx_inv_w = 1.0;\n"
|
||||
" } else {\n"
|
||||
" vtx_inv_w = 1.0 / oPos.w;\n"
|
||||
" }\n"
|
||||
" vtx_inv_w_flat = vtx_inv_w;\n");
|
||||
}
|
||||
|
||||
static void append_skinning_code(MString* str, bool mix,
|
||||
|
|
|
@ -735,12 +735,7 @@ static const char* vsh_header =
|
|||
"#define RCC(dest, mask, src) dest.mask = _RCC(_in(src).x).mask\n"
|
||||
"vec4 _RCC(float src)\n"
|
||||
"{\n"
|
||||
" float t = 1.0 / src;\n"
|
||||
" if (t > 0.0) {\n"
|
||||
" t = clamp(t, 5.42101e-020, 1.884467e+019);\n"
|
||||
" } else {\n"
|
||||
" t = clamp(t, -1.884467e+019, -5.42101e-020);\n"
|
||||
" }\n"
|
||||
" float t = clampAwayZeroInf(1.0 / src);\n"
|
||||
" return vec4(t);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
|
@ -797,7 +792,6 @@ static const char* vsh_header =
|
|||
void pgraph_gen_vsh_prog_glsl(uint16_t version,
|
||||
const uint32_t *tokens,
|
||||
unsigned int length,
|
||||
bool z_perspective,
|
||||
bool vulkan,
|
||||
MString *header, MString *body)
|
||||
{
|
||||
|
@ -826,18 +820,6 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version,
|
|||
}
|
||||
assert(has_final);
|
||||
|
||||
/* pre-divide and output the generated W so we can do persepctive correct
|
||||
* interpolation manually. OpenGL can't, since we give it a W of 1 to work
|
||||
* around the perspective divide */
|
||||
mstring_append(body,
|
||||
" if (oPos.w == 0.0 || isinf(oPos.w)) {\n"
|
||||
" vtx_inv_w = 1.0;\n"
|
||||
" } else {\n"
|
||||
" vtx_inv_w = 1.0 / oPos.w;\n"
|
||||
" }\n"
|
||||
" vtx_inv_w_flat = vtx_inv_w;\n"
|
||||
);
|
||||
|
||||
mstring_append(body,
|
||||
/* the shaders leave the result in screen space, while
|
||||
* opengl expects it in clip space.
|
||||
|
@ -854,32 +836,17 @@ void pgraph_gen_vsh_prog_glsl(uint16_t version,
|
|||
"/ surfaceSize.y;\n");
|
||||
}
|
||||
|
||||
if (z_perspective) {
|
||||
mstring_append(body, " oPos.z = oPos.w;\n");
|
||||
}
|
||||
|
||||
mstring_append(body,
|
||||
" if (clipRange.y != clipRange.x) {\n");
|
||||
if (vulkan) {
|
||||
mstring_append(body, " oPos.z /= clipRange.y;\n");
|
||||
} else {
|
||||
mstring_append(body,
|
||||
" oPos.z = (oPos.z - clipRange.x)/(0.5*(clipRange.y "
|
||||
"- clipRange.x)) - 1;\n");
|
||||
}
|
||||
mstring_append(body,
|
||||
" }\n"
|
||||
" oPos.z = oPos.z / clipRange.y;\n"
|
||||
" oPos.w = clampAwayZeroInf(oPos.w);\n"
|
||||
|
||||
/* Correct for the perspective divide */
|
||||
" if (oPos.w < 0.0) {\n"
|
||||
/* undo the perspective divide in the case where the point would be
|
||||
* clipped so opengl can clip it correctly */
|
||||
" oPos.xyz *= oPos.w;\n"
|
||||
" } else {\n"
|
||||
/* we don't want the OpenGL perspective divide to happen, but we
|
||||
* can't multiply by W because it could be meaningless here */
|
||||
" oPos.w = 1.0;\n"
|
||||
" }\n"
|
||||
/* Undo perspective divide by w.
|
||||
* Note that games may also have vertex shaders that do
|
||||
* not divide by w (such as 2D-graphics menus or overlays), but since
|
||||
* OpenGL will later on divide by the same w, we get back the same
|
||||
* screen space coordinates (perhaps with some loss of floating point
|
||||
* precision, though.)
|
||||
*/
|
||||
" oPos.xyz *= oPos.w;\n"
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#define HW_XBOX_NV2A_PGRAPH_GLSL_VSH_PROG_H
|
||||
|
||||
void pgraph_gen_vsh_prog_glsl(uint16_t version, const uint32_t *tokens,
|
||||
unsigned int length, bool z_perspective,
|
||||
unsigned int length,
|
||||
bool vulkan, MString *header, MString *body);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -72,6 +72,16 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs)
|
|||
" float y = float(bitfieldExtract(cmp, 11, 11)) / 1023.0;\n"
|
||||
" float z = float(bitfieldExtract(cmp, 22, 10)) / 511.0;\n"
|
||||
" return vec4(x, y, z, 1);\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
// Clamp to range [2^(-64), 2^64] or [-2^64, -2^(-64)].
|
||||
"float clampAwayZeroInf(float t) {\n"
|
||||
" if (t > 0.0 || floatBitsToUint(t) == 0) {\n"
|
||||
" t = clamp(t, uintBitsToFloat(0x1F800000), uintBitsToFloat(0x5F800000));\n"
|
||||
" } else {\n"
|
||||
" t = clamp(t, uintBitsToFloat(0xDF800000), uintBitsToFloat(0x9F800000));\n"
|
||||
" }\n"
|
||||
" return t;\n"
|
||||
"}\n");
|
||||
|
||||
pgraph_get_glsl_vtx_header(header, state->vulkan, state->smooth_shading,
|
||||
|
@ -79,8 +89,6 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs)
|
|||
|
||||
if (prefix_outputs) {
|
||||
mstring_append(header,
|
||||
"#define vtx_inv_w v_vtx_inv_w\n"
|
||||
"#define vtx_inv_w_flat v_vtx_inv_w_flat\n"
|
||||
"#define vtxD0 v_vtxD0\n"
|
||||
"#define vtxD1 v_vtxD1\n"
|
||||
"#define vtxB0 v_vtxB0\n"
|
||||
|
@ -142,7 +150,7 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs)
|
|||
} else if (state->vertex_program) {
|
||||
pgraph_gen_vsh_prog_glsl(VSH_VERSION_XVS,
|
||||
(uint32_t *)state->program_data,
|
||||
state->program_length, state->z_perspective,
|
||||
state->program_length,
|
||||
state->vulkan, header, body);
|
||||
} else {
|
||||
assert(false);
|
||||
|
@ -233,27 +241,30 @@ MString *pgraph_gen_vsh_glsl(const ShaderState *state, bool prefix_outputs)
|
|||
}
|
||||
|
||||
/* Set outputs */
|
||||
const char *shade_model_mult = state->smooth_shading ? "vtx_inv_w" : "vtx_inv_w_flat";
|
||||
mstring_append_fmt(body, "\n"
|
||||
" vtxD0 = clamp(oD0, 0.0, 1.0) * %s;\n"
|
||||
" vtxD1 = clamp(oD1, 0.0, 1.0) * %s;\n"
|
||||
" vtxB0 = clamp(oB0, 0.0, 1.0) * %s;\n"
|
||||
" vtxB1 = clamp(oB1, 0.0, 1.0) * %s;\n"
|
||||
" vtxFog = oFog.x * vtx_inv_w;\n"
|
||||
" vtxT0 = oT0 * vtx_inv_w;\n"
|
||||
" vtxT1 = oT1 * vtx_inv_w;\n"
|
||||
" vtxT2 = oT2 * vtx_inv_w;\n"
|
||||
" vtxT3 = oT3 * vtx_inv_w;\n"
|
||||
" gl_Position = oPos;\n"
|
||||
" gl_PointSize = oPts.x;\n"
|
||||
// " gl_ClipDistance[0] = oPos.z - oPos.w*clipRange.z;\n" // Near
|
||||
// " gl_ClipDistance[1] = oPos.w*clipRange.w - oPos.z;\n" // Far
|
||||
"\n"
|
||||
"}\n",
|
||||
shade_model_mult,
|
||||
shade_model_mult,
|
||||
shade_model_mult,
|
||||
shade_model_mult);
|
||||
mstring_append(body, "\n"
|
||||
" vtxD0 = clamp(oD0, 0.0, 1.0);\n"
|
||||
" vtxD1 = clamp(oD1, 0.0, 1.0);\n"
|
||||
" vtxB0 = clamp(oB0, 0.0, 1.0);\n"
|
||||
" vtxB1 = clamp(oB1, 0.0, 1.0);\n"
|
||||
" vtxFog = oFog.x;\n"
|
||||
" vtxT0 = oT0;\n"
|
||||
" vtxT1 = oT1;\n"
|
||||
" vtxT2 = oT2;\n"
|
||||
" vtxT3 = oT3;\n"
|
||||
" gl_PointSize = oPts.x;\n"
|
||||
);
|
||||
|
||||
if (state->vulkan) {
|
||||
mstring_append(body,
|
||||
" gl_Position = oPos;\n"
|
||||
);
|
||||
} else {
|
||||
mstring_append(body,
|
||||
" gl_Position = vec4(oPos.x, oPos.y, 2.0*oPos.z - oPos.w, oPos.w);\n"
|
||||
);
|
||||
}
|
||||
|
||||
mstring_append(body, "}\n");
|
||||
|
||||
/* Return combined header + source */
|
||||
if (state->vulkan) {
|
||||
|
|
|
@ -85,6 +85,8 @@ typedef struct PshState {
|
|||
bool window_clip_exclusive;
|
||||
|
||||
bool smooth_shading;
|
||||
bool depth_clipping;
|
||||
bool z_perspective;
|
||||
} PshState;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -94,6 +94,7 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg)
|
|||
state.vertex_program = vertex_program,
|
||||
state.z_perspective = pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
|
||||
NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE;
|
||||
state.psh.z_perspective = state.z_perspective;
|
||||
|
||||
state.point_params_enable = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CSV0_D),
|
||||
NV_PGRAPH_CSV0_D_POINTPARAMSENABLE);
|
||||
|
@ -117,6 +118,10 @@ ShaderState pgraph_get_shader_state(PGRAPHState *pg)
|
|||
NV_PGRAPH_CONTROL_3_SHADEMODE_SMOOTH;
|
||||
state.psh.smooth_shading = state.smooth_shading;
|
||||
|
||||
state.psh.depth_clipping = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_ZCOMPRESSOCCLUDE),
|
||||
NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN) ==
|
||||
NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN_CULL;
|
||||
|
||||
state.program_length = 0;
|
||||
|
||||
if (vertex_program) {
|
||||
|
|
|
@ -635,11 +635,9 @@ static bool check_pipeline_dirty(PGRAPHState *pg)
|
|||
}
|
||||
|
||||
const unsigned int regs[] = {
|
||||
NV_PGRAPH_BLEND, NV_PGRAPH_BLENDCOLOR,
|
||||
NV_PGRAPH_CONTROL_0, NV_PGRAPH_CONTROL_1,
|
||||
NV_PGRAPH_CONTROL_2, NV_PGRAPH_CONTROL_3,
|
||||
NV_PGRAPH_SETUPRASTER, NV_PGRAPH_ZCOMPRESSOCCLUDE,
|
||||
NV_PGRAPH_ZOFFSETBIAS, NV_PGRAPH_ZOFFSETFACTOR,
|
||||
NV_PGRAPH_BLEND, NV_PGRAPH_BLENDCOLOR, NV_PGRAPH_CONTROL_0,
|
||||
NV_PGRAPH_CONTROL_1, NV_PGRAPH_CONTROL_2, NV_PGRAPH_CONTROL_3,
|
||||
NV_PGRAPH_SETUPRASTER, NV_PGRAPH_ZOFFSETBIAS, NV_PGRAPH_ZOFFSETFACTOR,
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(regs); i++) {
|
||||
|
@ -682,11 +680,9 @@ static void init_pipeline_key(PGRAPHState *pg, PipelineKey *key)
|
|||
// FIXME: Register masking
|
||||
// FIXME: Use more dynamic state updates
|
||||
const int regs[] = {
|
||||
NV_PGRAPH_BLEND, NV_PGRAPH_BLENDCOLOR,
|
||||
NV_PGRAPH_CONTROL_0, NV_PGRAPH_CONTROL_1,
|
||||
NV_PGRAPH_CONTROL_2, NV_PGRAPH_CONTROL_3,
|
||||
NV_PGRAPH_SETUPRASTER, NV_PGRAPH_ZCOMPRESSOCCLUDE,
|
||||
NV_PGRAPH_ZOFFSETBIAS, NV_PGRAPH_ZOFFSETFACTOR,
|
||||
NV_PGRAPH_BLEND, NV_PGRAPH_BLENDCOLOR, NV_PGRAPH_CONTROL_0,
|
||||
NV_PGRAPH_CONTROL_1, NV_PGRAPH_CONTROL_2, NV_PGRAPH_CONTROL_3,
|
||||
NV_PGRAPH_SETUPRASTER, NV_PGRAPH_ZOFFSETBIAS, NV_PGRAPH_ZOFFSETFACTOR,
|
||||
};
|
||||
assert(ARRAY_SIZE(regs) == ARRAY_SIZE(key->regs));
|
||||
for (int i = 0; i < ARRAY_SIZE(regs); i++) {
|
||||
|
@ -816,7 +812,7 @@ static void create_pipeline(PGRAPHState *pg)
|
|||
|
||||
VkPipelineRasterizationStateCreateInfo rasterizer = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.depthClampEnable = VK_FALSE,
|
||||
.depthClampEnable = VK_TRUE,
|
||||
.rasterizerDiscardEnable = VK_FALSE,
|
||||
.polygonMode = pgraph_polygon_mode_vk_map[r->shader_binding->state
|
||||
.polygon_front_mode],
|
||||
|
@ -958,10 +954,6 @@ static void create_pipeline(PGRAPHState *pg)
|
|||
.pDynamicStates = dynamic_states,
|
||||
};
|
||||
|
||||
// /* Clipping */
|
||||
// glEnable(GL_CLIP_DISTANCE0);
|
||||
// glEnable(GL_CLIP_DISTANCE1);
|
||||
|
||||
// /* Polygon offset */
|
||||
// /* FIXME: GL implementation-specific, maybe do this in VS? */
|
||||
// if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
|
||||
|
@ -983,12 +975,6 @@ static void create_pipeline(PGRAPHState *pg)
|
|||
rasterizer.depthBiasConstantFactor = zbias;
|
||||
}
|
||||
|
||||
if (GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_ZCOMPRESSOCCLUDE),
|
||||
NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN) ==
|
||||
NV_PGRAPH_ZCOMPRESSOCCLUDE_ZCLAMP_EN_CLAMP) {
|
||||
rasterizer.depthClampEnable = VK_TRUE;
|
||||
}
|
||||
|
||||
// FIXME: Dither
|
||||
// if (pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
|
||||
// NV_PGRAPH_CONTROL_0_DITHERENABLE))
|
||||
|
|
|
@ -65,7 +65,7 @@ typedef struct PipelineKey {
|
|||
bool clear;
|
||||
RenderPassState render_pass_state;
|
||||
ShaderState shader_state;
|
||||
uint32_t regs[10];
|
||||
uint32_t regs[9];
|
||||
VkVertexInputBindingDescription binding_descriptions[NV2A_VERTEXSHADER_ATTRIBUTES];
|
||||
VkVertexInputAttributeDescription attribute_descriptions[NV2A_VERTEXSHADER_ATTRIBUTES];
|
||||
} PipelineKey;
|
||||
|
@ -173,6 +173,8 @@ typedef struct ShaderBinding {
|
|||
|
||||
int surface_size_loc;
|
||||
int clip_range_loc;
|
||||
int clip_range_floc;
|
||||
int depth_offset_loc;
|
||||
|
||||
int vsh_constant_loc;
|
||||
uint32_t vsh_constants[NV2A_VERTEXSHADER_CONSTANTS][4];
|
||||
|
|
|
@ -276,6 +276,10 @@ static void update_shader_constant_locations(ShaderBinding *binding)
|
|||
uniform_index(&binding->vertex->uniforms, "surfaceSize");
|
||||
binding->clip_range_loc =
|
||||
uniform_index(&binding->vertex->uniforms, "clipRange");
|
||||
binding->clip_range_floc =
|
||||
uniform_index(&binding->fragment->uniforms, "clipRange");
|
||||
binding->depth_offset_loc =
|
||||
uniform_index(&binding->fragment->uniforms, "depthOffset");
|
||||
binding->fog_param_loc =
|
||||
uniform_index(&binding->vertex->uniforms, "fogParam");
|
||||
|
||||
|
@ -477,10 +481,9 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
|
|||
}
|
||||
}
|
||||
if (binding->alpha_ref_loc != -1) {
|
||||
float alpha_ref = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0),
|
||||
NV_PGRAPH_CONTROL_0_ALPHAREF) /
|
||||
255.0;
|
||||
uniform1f(&binding->fragment->uniforms, binding->alpha_ref_loc,
|
||||
int alpha_ref = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0),
|
||||
NV_PGRAPH_CONTROL_0_ALPHAREF);
|
||||
uniform1i(&binding->fragment->uniforms, binding->alpha_ref_loc,
|
||||
alpha_ref);
|
||||
}
|
||||
|
||||
|
@ -638,14 +641,47 @@ static void shader_update_constants(PGRAPHState *pg, ShaderBinding *binding,
|
|||
pg->surface_binding_dim.height / aa_height);
|
||||
}
|
||||
|
||||
if (binding->clip_range_loc != -1) {
|
||||
if (binding->clip_range_loc != -1 || binding->clip_range_floc != -1) {
|
||||
uint32_t v[2];
|
||||
v[0] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMIN);
|
||||
v[1] = pgraph_reg_r(pg, NV_PGRAPH_ZCLIPMAX);
|
||||
float zclip_min = *(float *)&v[0] / zmax * 2.0 - 1.0;
|
||||
float zclip_max = *(float *)&v[1] / zmax * 2.0 - 1.0;
|
||||
uniform4f(&binding->vertex->uniforms, binding->clip_range_loc, 0,
|
||||
zmax, zclip_min, zclip_max);
|
||||
float zclip_min = *(float *)&v[0];
|
||||
float zclip_max = *(float *)&v[1];
|
||||
|
||||
if (binding->clip_range_loc != -1) {
|
||||
uniform4f(&binding->vertex->uniforms, binding->clip_range_loc, 0,
|
||||
zmax, zclip_min, zclip_max);
|
||||
}
|
||||
if (binding->clip_range_floc != -1) {
|
||||
uniform4f(&binding->fragment->uniforms, binding->clip_range_floc, 0,
|
||||
zmax, zclip_min, zclip_max);
|
||||
}
|
||||
}
|
||||
|
||||
if (binding->depth_offset_loc != -1) {
|
||||
float zbias = 0.0f;
|
||||
|
||||
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
|
||||
(NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE |
|
||||
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) {
|
||||
uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS);
|
||||
zbias = *(float *)&zbias_u32;
|
||||
|
||||
if (pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR) != 0 &&
|
||||
(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
|
||||
NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE)) {
|
||||
/* TODO: emulate zfactor when z_perspective true, i.e.
|
||||
* w-buffering. Perhaps calculate an additional offset based on
|
||||
* triangle orientation in geometry shader and pass the result
|
||||
* to fragment shader and add it to gl_FragDepth as well.
|
||||
*/
|
||||
NV2A_UNIMPLEMENTED("NV_PGRAPH_ZOFFSETFACTOR for w-buffering");
|
||||
}
|
||||
}
|
||||
|
||||
uniform1f(&binding->fragment->uniforms, binding->depth_offset_loc,
|
||||
zbias);
|
||||
}
|
||||
|
||||
/* Clipping regions */
|
||||
|
@ -725,6 +761,7 @@ static bool check_shaders_dirty(PGRAPHState *pg)
|
|||
NV_PGRAPH_SHADERCTL,
|
||||
NV_PGRAPH_SHADERPROG,
|
||||
NV_PGRAPH_SHADOWCTL,
|
||||
NV_PGRAPH_ZCOMPRESSOCCLUDE,
|
||||
};
|
||||
for (int i = 0; i < ARRAY_SIZE(regs); i++) {
|
||||
if (pgraph_is_reg_dirty(pg, regs[i])) {
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Simple HTTP handlers
|
||||
*
|
||||
* Copyright (c) 2025 Matt Borgerson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef QEMU_HTTP_H
|
||||
#define QEMU_HTTP_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct http_progress_cb_info {
|
||||
int (*progress)(struct http_progress_cb_info *progress_info);
|
||||
void *userptr;
|
||||
size_t dlnow;
|
||||
size_t dltotal;
|
||||
size_t ulnow;
|
||||
size_t ultotal;
|
||||
} http_progress_cb_info;
|
||||
|
||||
int http_get(const char *url, GByteArray *response_body,
|
||||
http_progress_cb_info *progress_info, Error **errp);
|
||||
int http_post_json(const char *url, const char *json_data, Error **errp);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -1,22 +0,0 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 yhirose
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
COPYRIGHT AND PERMISSION NOTICE
|
||||
|
||||
Copyright (c) 1996 - 2025, Daniel Stenberg, <daniel@haxx.se>, and many
|
||||
contributors, see the THANKS file.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Permission to use, copy, modify, and distribute this software for any purpose
|
||||
with or without fee is hereby granted, provided that the above copyright
|
||||
notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of a copyright holder shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
||||
in this Software without prior written authorization of the copyright holder.
|
|
@ -1,177 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
49
meson.build
49
meson.build
|
@ -1383,11 +1383,39 @@ if not get_option('blkio').auto() or have_block
|
|||
method: 'pkg-config',
|
||||
required: get_option('blkio'))
|
||||
endif
|
||||
curl = not_found
|
||||
if not get_option('curl').auto() or have_block
|
||||
curl = dependency('libcurl', version: '>=7.29.0',
|
||||
method: 'pkg-config',
|
||||
required: get_option('curl'))
|
||||
curl = dependency('libcurl', version: '>=7.29.0',
|
||||
method: 'pkg-config',
|
||||
required: false)
|
||||
if not curl.found()
|
||||
if host_os == 'windows'
|
||||
curl_platform_opts = ['schannel=enabled', 'sspi=enabled']
|
||||
elif host_os == 'darwin'
|
||||
curl_platform_opts = ['secure-transport=enabled']
|
||||
else
|
||||
curl_platform_opts = ['openssl=enabled']
|
||||
endif
|
||||
curl_sub = subproject('curl',
|
||||
default_options: [
|
||||
'ssl=enabled',
|
||||
'http=enabled',
|
||||
'ftp=enabled',
|
||||
'dict=disabled',
|
||||
'file=disabled',
|
||||
'gopher=disabled',
|
||||
'imap=disabled',
|
||||
'ldap=disabled',
|
||||
'ldaps=disabled',
|
||||
'mqtt=disabled',
|
||||
'pop3=disabled',
|
||||
'rtmp=disabled',
|
||||
'rtsp=disabled',
|
||||
'smb=disabled',
|
||||
'smtp=disabled',
|
||||
'telnet=disabled',
|
||||
'tftp=disabled',
|
||||
'default_library=static',
|
||||
] + curl_platform_opts)
|
||||
curl = curl_sub.get_variable('curl_dep')
|
||||
endif
|
||||
libudev = not_found
|
||||
if host_os == 'linux' and (have_system or have_tools)
|
||||
|
@ -2297,10 +2325,11 @@ elif host_os == 'linux'
|
|||
endif
|
||||
|
||||
if vulkan.found()
|
||||
libglslang = dependency('glslang', version: '>=15.0.0', required: false)
|
||||
if not libglslang.found()
|
||||
# FIXME: Get spirv-tools to enable opt.
|
||||
glslang_opts = cmake.subproject_options()
|
||||
glslang_opts.add_cmake_defines({'ENABLE_OPT': false})
|
||||
glslang_opts.add_cmake_defines({'ENABLE_OPT': false, 'ENABLE_HLSL': false})
|
||||
glslang_subpro = cmake.subproject('glslang', options: glslang_opts)
|
||||
libglslang = declare_dependency(link_with: [
|
||||
glslang_subpro.target('glslang'),
|
||||
|
@ -2330,8 +2359,6 @@ if vulkan.found()
|
|||
dependencies: vulkan)
|
||||
endif
|
||||
|
||||
openssl = dependency('openssl', method: 'pkg-config', required: true)
|
||||
|
||||
if host_os == 'windows'
|
||||
libpcap = declare_dependency(include_directories: 'winpcap-loader/include',
|
||||
link_args: ['-lws2_32'])
|
||||
|
@ -3524,11 +3551,9 @@ if have_libvduse
|
|||
libvduse = libvduse_proj.get_variable('libvduse_dep')
|
||||
endif
|
||||
|
||||
tomlplusplus_proj = subproject('tomlplusplus', default_options: ['default_library=static'])
|
||||
tomlplusplus = tomlplusplus_proj.get_variable('tomlplusplus_dep')
|
||||
tomlplusplus = dependency('tomlplusplus', fallback: ['tomlplusplus', 'tomlplusplus_dep'], default_options: ['default_library=static'])
|
||||
|
||||
xxhash_proj = subproject('xxhash', default_options: ['default_library=static'])
|
||||
xxhash = xxhash_proj.get_variable('xxhash_dep')
|
||||
xxhash = dependency('libxxhash', fallback: ['xxhash', 'xxhash_dep'], default_options: ['default_library=static'])
|
||||
|
||||
#####################
|
||||
# Generated sources #
|
||||
|
|
|
@ -36,7 +36,7 @@ sub_deinit=""
|
|||
# xemu only
|
||||
subprojects="keycodemapdb berkeley-softfloat-3 berkeley-testfloat-3
|
||||
glslang SPIRV-Reflect volk VulkanMemoryAllocator nv2a_vsh_cpu
|
||||
tomlplusplus cpp-httplib xxhash imgui implot genconfig"
|
||||
tomlplusplus xxhash imgui implot genconfig json"
|
||||
|
||||
function cleanup() {
|
||||
local status=$?
|
||||
|
|
|
@ -92,7 +92,7 @@ class LibInstaller:
|
|||
shell=True, check=True)
|
||||
|
||||
def is_pkg_skipped(self, pkg_name):
|
||||
return any(pkg_name.startswith(n) for n in ('python', 'ncurses', 'mesa', 'llvm'))
|
||||
return any(pkg_name.startswith(n) for n in ('python', 'ncurses', 'mesa', 'llvm', 'libsndfile'))
|
||||
|
||||
def install_pkg(self, pkg_name):
|
||||
if self.is_pkg_installed(pkg_name):
|
||||
|
@ -185,7 +185,6 @@ def main():
|
|||
'libsamplerate',
|
||||
'libpixman',
|
||||
'libepoxy',
|
||||
'openssl11',
|
||||
'libpcap',
|
||||
'libslirp'])
|
||||
|
||||
|
|
|
@ -201,12 +201,6 @@ Lib('implot', 'https://github.com/epezent/implot',
|
|||
submodule=Submodule('subprojects/implot.wrap')
|
||||
),
|
||||
|
||||
Lib('cpp-httplib', 'https://github.com/yhirose/cpp-httplib',
|
||||
mit, 'https://raw.githubusercontent.com/yhirose/cpp-httplib/master/LICENSE',
|
||||
ships_static=all_platforms,
|
||||
submodule=Submodule('subprojects/cpp-httplib.wrap')
|
||||
),
|
||||
|
||||
Lib('noc', 'https://github.com/guillaumechereau/noc/blob/master/noc_file_dialog.h',
|
||||
mit, 'https://raw.githubusercontent.com/xemu-project/xemu/master/ui/noc_file_dialog.h', license_lines=(1,22),
|
||||
ships_static=all_platforms,
|
||||
|
@ -347,16 +341,6 @@ Lib('libsamplerate', 'https://github.com/libsndfile/libsamplerate',
|
|||
pkg_mac='libsamplerate',
|
||||
),
|
||||
|
||||
Lib('openssl', 'https://www.openssl.org/',
|
||||
apache2, 'https://raw.githubusercontent.com/openssl/openssl/master/LICENSE.txt',
|
||||
ships_static={windows}, ships_dynamic={macos},
|
||||
pkgconfig=PkgConfig('openssl'),
|
||||
pkg_win='openssl',
|
||||
pkg_mac='openssl',
|
||||
pkg_ubuntu='libssl-dev'
|
||||
),
|
||||
|
||||
# openssl dep
|
||||
Lib('zlib', 'https://zlib.net/',
|
||||
zlib, 'https://raw.githubusercontent.com/madler/zlib/master/README', license_lines=(87,106),
|
||||
ships_static={windows}, ships_dynamic={macos},
|
||||
|
@ -380,6 +364,12 @@ Lib('miniz', 'https://github.com/richgel999/miniz',
|
|||
ships_static={windows}, platform={windows},
|
||||
version='2.1.0'
|
||||
),
|
||||
|
||||
Lib('libcurl', 'https://curl.se/',
|
||||
mit, 'https://raw.githubusercontent.com/curl/curl/refs/heads/master/COPYING',
|
||||
ships_static={windows}, platform={windows},
|
||||
submodule=Submodule('subprojects/curl.wrap')
|
||||
),
|
||||
]
|
||||
|
||||
def gen_license():
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
set -ex
|
||||
# uv tool install fonttools
|
||||
FONT_INPUT=font_awesome_6_1_1_solid.otf
|
||||
FONT_OUTPUT=font_awesome_6_1_1_solid.min.otf
|
||||
GLYPHS=$(grep -rhoE "ICON_FA_\w+" ../ui/xui | sort | uniq | sed -E 's/^ICON_FA_//; s/_/-/g; s/.*/\L&/' | paste -sd ",")
|
||||
pyftsubset $FONT_INPUT --output-file=$FONT_OUTPUT --glyphs=$GLYPHS
|
|
@ -24,8 +24,9 @@ volk
|
|||
VulkanMemoryAllocator
|
||||
nv2a_vsh_cpu
|
||||
tomlplusplus
|
||||
cpp-httplib
|
||||
xxHash-*
|
||||
imgui
|
||||
implot
|
||||
genconfig
|
||||
curl-*
|
||||
json-*
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[wrap-git]
|
||||
url=https://github.com/yhirose/cpp-httplib
|
||||
revision=0f1b62c2b3d0898cbab7aa685c2593303ffdc1a2
|
||||
depth=1
|
|
@ -0,0 +1,13 @@
|
|||
[wrap-file]
|
||||
directory = curl-8.10.1
|
||||
source_url = https://github.com/curl/curl/releases/download/curl-8_10_1/curl-8.10.1.tar.xz
|
||||
source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/curl_8.10.1-1/curl-8.10.1.tar.xz
|
||||
source_filename = curl-8.10.1.tar.xz
|
||||
source_hash = 73a4b0e99596a09fa5924a4fb7e4b995a85fda0d18a2c02ab9cf134bebce04ee
|
||||
patch_filename = curl_8.10.1-1_patch.zip
|
||||
patch_url = https://wrapdb.mesonbuild.com/v2/curl_8.10.1-1/get_patch
|
||||
patch_hash = 707c28f35fc9b0e8d68c0c2800712007612f922a31da9637ce706a2159f3ddd8
|
||||
wrapdb_version = 8.10.1-1
|
||||
|
||||
[provide]
|
||||
dependency_names = libcurl
|
|
@ -1,4 +1,4 @@
|
|||
[wrap-git]
|
||||
url=https://github.com/xemu-project/imgui
|
||||
revision=80cbdab5ecd70db79917c448c333163995e605a5
|
||||
revision=7219d617a32b594f9a80b2356aec42e0e939e938
|
||||
depth=1
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[wrap-git]
|
||||
url=https://github.com/xemu-project/implot
|
||||
revision=006a1c23e5706bbe816968163b4d589162257a57
|
||||
revision=8553562dbb2025fd520f4bed57b094767b96c670
|
||||
depth=1
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
[wrap-file]
|
||||
directory = json-3.2.0
|
||||
source_url = https://github.com/nlohmann/json/archive/v3.2.0/json-3.2.0.tar.gz
|
||||
source_filename = json-3.2.0.tar.gz
|
||||
source_hash = 2de558ff3b3b32eebfb51cf2ceb835a0fa5170e6b8712b02be9c2c07fcfe52a1
|
||||
patch_url = https://wrapdb.mesonbuild.com/v2/json_3.2.0-1/get_patch
|
||||
patch_filename = json-3.2.0-1-wrap.zip
|
||||
patch_hash = f601837156f1f391ea9923c6d602450b1357537b1821d727251e75d97cb10f67
|
||||
|
||||
[provide]
|
||||
nlohmann_json = nlohmann_json_dep
|
|
@ -50,7 +50,7 @@ elif host_os == 'windows'
|
|||
elif host_os == 'darwin'
|
||||
xemu_ss.add(files('xemu-os-utils-macos.m'))
|
||||
endif
|
||||
xemu_ss.add(imgui, implot, stb_image, noc, sdl, opengl, openssl, fa, fpng, json, httplib, fatx)
|
||||
xemu_ss.add(imgui, implot, stb_image, noc, sdl, opengl, fa, fpng, json, fatx)
|
||||
system_ss.add_all(xemu_ss)
|
||||
|
||||
system_ss.add(when: pixman, if_true: files('console-vc.c'), if_false: files('console-vc-stubs.c'))
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,14 +29,6 @@ endif
|
|||
libfpng = static_library('fpng', sources: 'fpng/fpng.cpp', cpp_args: libfpng_cpp_args)
|
||||
fpng = declare_dependency(include_directories: 'fpng', link_with: libfpng)
|
||||
|
||||
json = declare_dependency(include_directories: 'json')
|
||||
|
||||
httplib_proj = subproject('cpp-httplib', default_options: ['cpp-httplib_openssl=enabled'])
|
||||
httplib_deps = [httplib_proj.get_variable('cpp_httplib_dep')]
|
||||
if host_os == 'windows'
|
||||
httplib_deps += [crypt32]
|
||||
endif
|
||||
httplib = declare_dependency(dependencies: httplib_deps)
|
||||
|
||||
libfatx = static_library('fatx', sources: 'fatx/fatx.c')
|
||||
json = dependency('nlohmann_json', required: true)
|
||||
libfatx = static_library('fatx', sources: files('fatx/fatx.c') + genh)
|
||||
fatx = declare_dependency(include_directories: 'fatx', link_with: libfatx)
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "data/Roboto-Medium.ttf.h"
|
||||
#include "data/RobotoCondensed-Regular.ttf.h"
|
||||
#include "data/font_awesome_6_1_1_solid.otf.h"
|
||||
#include "data/font_awesome_6_1_1_solid.min.otf.h"
|
||||
#include "data/abxy.ttf.h"
|
||||
|
||||
FontManager g_font_mgr;
|
||||
|
@ -81,8 +81,8 @@ void FontManager::Rebuild()
|
|||
ImVec2(0, -3 * g_viewport_mgr.m_scale * m_font_scale);
|
||||
config.GlyphMinAdvanceX = 32.0f * g_viewport_mgr.m_scale * m_font_scale;
|
||||
static const ImWchar icon_ranges[] = { ICON_MIN_FA, ICON_MAX_FA, 0 };
|
||||
io.Fonts->AddFontFromMemoryTTF((void *)font_awesome_6_1_1_solid_data,
|
||||
font_awesome_6_1_1_solid_size,
|
||||
io.Fonts->AddFontFromMemoryTTF((void *)font_awesome_6_1_1_solid_min_data,
|
||||
font_awesome_6_1_1_solid_min_size,
|
||||
18.0f * g_viewport_mgr.m_scale *
|
||||
m_font_scale,
|
||||
&config, icon_ranges);
|
||||
|
|
|
@ -130,12 +130,15 @@ void MainMenuInputView::Draw()
|
|||
float x = b_x + i * b_x_stride;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button,
|
||||
is_selected ? color_active : color_inactive);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
|
||||
g_viewport_mgr.Scale(ImVec2(port_padding, port_padding)));
|
||||
bool activated = ImGui::ImageButton(
|
||||
"port_image_button",
|
||||
id,
|
||||
ImVec2(b_w * g_viewport_mgr.m_scale, b_h * g_viewport_mgr.m_scale),
|
||||
ImVec2(x / t_w, (b_y + b_h) / t_h),
|
||||
ImVec2((x + b_w) / t_w, b_y / t_h),
|
||||
port_padding * g_viewport_mgr.m_scale);
|
||||
ImVec2((x + b_w) / t_w, b_y / t_h));
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
if (activated) {
|
||||
|
@ -1382,7 +1385,7 @@ void MainMenuAboutView::Draw()
|
|||
SectionTitle("Build Information");
|
||||
ImGui::PushFont(g_font_mgr.m_fixed_width_font);
|
||||
ImGui::InputTextMultiline("##build_info", (char *)build_info_text,
|
||||
strlen(build_info_text),
|
||||
strlen(build_info_text) + 1,
|
||||
ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 5),
|
||||
ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::PopFont();
|
||||
|
@ -1390,7 +1393,7 @@ void MainMenuAboutView::Draw()
|
|||
SectionTitle("System Information");
|
||||
ImGui::PushFont(g_font_mgr.m_fixed_width_font);
|
||||
ImGui::InputTextMultiline("###systeminformation", (char *)sys_info_text,
|
||||
strlen(sys_info_text),
|
||||
strlen(sys_info_text) + 1,
|
||||
ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 8),
|
||||
ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::PopFont();
|
||||
|
@ -1398,7 +1401,7 @@ void MainMenuAboutView::Draw()
|
|||
SectionTitle("Config Information");
|
||||
ImGui::PushFont(g_font_mgr.m_fixed_width_font);
|
||||
ImGui::InputTextMultiline("##config_info", (char *)m_config_info_text,
|
||||
strlen(build_info_text),
|
||||
strlen(build_info_text) + 1,
|
||||
ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 3),
|
||||
ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::PopFont();
|
||||
|
|
|
@ -208,7 +208,7 @@ void xemu_hud_render(void)
|
|||
|
||||
ImGui_ImplOpenGL3_NewFrame();
|
||||
io.ConfigFlags &= ~ImGuiConfigFlags_NavEnableGamepad;
|
||||
ImGui_ImplSDL2_NewFrame(g_sdl_window);
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
g_input_mgr.Update();
|
||||
|
|
|
@ -75,7 +75,7 @@ void MonitorWindow::Draw()
|
|||
ImGui::PushID("#MonitorOutput");
|
||||
ImGui::InputTextMultiline("",
|
||||
buffer,
|
||||
buffer_len,
|
||||
buffer_len + 1,
|
||||
ImVec2(-1.0f, input_height),
|
||||
ImGuiInputTextFlags_ReadOnly|ImGuiInputTextFlags_NoUndoRedo);
|
||||
ImGui::PopID();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//
|
||||
// Title compatibility and bug report submission.
|
||||
//
|
||||
// Copyright (C) 2020-2021 Matt Borgerson
|
||||
// Copyright (C) 2020-2025 Matt Borgerson
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -18,15 +18,18 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/http.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <stdio.h>
|
||||
#include "reporting.hh"
|
||||
#include <httplib.h>
|
||||
#include <json.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
using json = nlohmann::json;
|
||||
|
||||
#define DEBUG_COMPAT_SERVICE 0
|
||||
static const char *compat_report_endpoint_url = "https://reports.xemu.app/compatibility";
|
||||
|
||||
CompatibilityReport::CompatibilityReport()
|
||||
{
|
||||
|
@ -61,38 +64,16 @@ const std::string &CompatibilityReport::GetSerializedReport()
|
|||
|
||||
bool CompatibilityReport::Send()
|
||||
{
|
||||
// Serialize the report
|
||||
const std::string &s = GetSerializedReport();
|
||||
|
||||
#if DEBUG_COMPAT_SERVICE
|
||||
httplib::SSLClient cli("127.0.0.1", 443);
|
||||
#else
|
||||
httplib::SSLClient cli("reports.xemu.app", 443);
|
||||
#endif
|
||||
|
||||
cli.set_follow_location(true);
|
||||
// cli.enable_server_certificate_verification(true); // FIXME: Package cert bundle
|
||||
|
||||
auto res = cli.Post("/compatibility", s, "application/json");
|
||||
|
||||
if (!res) {
|
||||
#if 0 // FIXME: Handle SSL certificate verification failure
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
auto result = cli.get_openssl_verify_result();
|
||||
if (result) {
|
||||
fprintf(stderr, "verify error: %s\n", X509_verify_cert_error_string(result));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int res = http_post_json(compat_report_endpoint_url, s.c_str(), NULL);
|
||||
if (res < 0) {
|
||||
result_code = -1;
|
||||
result_msg = "Failed to connect";
|
||||
return false;
|
||||
}
|
||||
|
||||
result_code = res->status;
|
||||
|
||||
switch(res->status) {
|
||||
switch(res) {
|
||||
case 200:
|
||||
result_msg = "Ok";
|
||||
return true;
|
||||
|
@ -110,7 +91,7 @@ bool CompatibilityReport::Send()
|
|||
result_msg = "Report too long";
|
||||
return false;
|
||||
default:
|
||||
result_msg = "Unknown error occured";
|
||||
result_msg = "Unknown error occurred";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// xemu User Interface
|
||||
//
|
||||
// Copyright (C) 2020-2022 Matt Borgerson
|
||||
// Copyright (C) 2020-2025 Matt Borgerson
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -17,6 +17,7 @@
|
|||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
#include "common.hh"
|
||||
#include "qemu/http.h"
|
||||
#include "update.hh"
|
||||
#include "viewport-manager.hh"
|
||||
#include <stdio.h>
|
||||
|
@ -26,13 +27,11 @@
|
|||
#include "xemu-version.h"
|
||||
|
||||
#if defined(_WIN32)
|
||||
const char *version_host = "raw.githubusercontent.com";
|
||||
const char *version_uri = "/xemu-project/xemu/ppa-snapshot/XEMU_VERSION";
|
||||
const char *download_host = "github.com";
|
||||
const char *version_url = "https://raw.githubusercontent.com/xemu-project/xemu/ppa-snapshot/XEMU_VERSION";
|
||||
#if defined(__x86_64__)
|
||||
const char *download_uri = "/xemu-project/xemu/releases/latest/download/xemu-win-x86_64-release.zip";
|
||||
const char *download_url = "https://github.com/xemu-project/xemu/releases/latest/download/xemu-win-x86_64-release.zip";
|
||||
#elif defined(__aarch64__)
|
||||
const char *download_uri = "/xemu-project/xemu/releases/latest/download/xemu-win-aarch64-release.zip";
|
||||
const char *download_url = "https://github.com/xemu-project/xemu/releases/latest/download/xemu-win-aarch64-release.zip";
|
||||
#else
|
||||
#error Unknown update path
|
||||
#endif
|
||||
|
@ -40,7 +39,6 @@ const char *download_uri = "/xemu-project/xemu/releases/latest/download/xemu-win
|
|||
FIXME
|
||||
#endif
|
||||
|
||||
#include <httplib.h>
|
||||
|
||||
#define DPRINTF(fmt, ...) fprintf(stderr, fmt, ##__VA_ARGS__);
|
||||
|
||||
|
@ -153,28 +151,26 @@ void *Updater::checker_thread_worker_func(void *updater)
|
|||
|
||||
void Updater::check_for_update_internal()
|
||||
{
|
||||
httplib::SSLClient cli(version_host, 443);
|
||||
cli.set_follow_location(true);
|
||||
auto res = cli.Get(version_uri, [this](uint64_t len, uint64_t total) {
|
||||
m_update_percentage = len*100/total;
|
||||
return !m_should_cancel;
|
||||
});
|
||||
g_autoptr(GByteArray) data = g_byte_array_new();
|
||||
int res = http_get(version_url, data, NULL, NULL);
|
||||
|
||||
if (m_should_cancel) {
|
||||
m_should_cancel = false;
|
||||
m_status = UPDATER_IDLE;
|
||||
goto finished;
|
||||
} else if (!res || res->status != 200) {
|
||||
} else if (res != 200) {
|
||||
m_status = UPDATER_ERROR;
|
||||
goto finished;
|
||||
}
|
||||
|
||||
if (strcmp(xemu_version, res->body.c_str())) {
|
||||
m_latest_version = std::string((const char *)data->data, data->len);
|
||||
|
||||
if (m_latest_version != xemu_version) {
|
||||
m_update_availability = UPDATE_AVAILABLE;
|
||||
} else {
|
||||
m_update_availability = UPDATE_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
m_latest_version = res->body;
|
||||
m_status = UPDATER_IDLE;
|
||||
finished:
|
||||
if (m_on_complete) {
|
||||
|
@ -198,27 +194,41 @@ void *Updater::update_thread_worker_func(void *updater)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int Updater::progress_cb(http_progress_cb_info *info)
|
||||
{
|
||||
if (info->dltotal == 0) {
|
||||
m_update_percentage = 0;
|
||||
} else {
|
||||
m_update_percentage = info->dlnow*100/info->dltotal;
|
||||
}
|
||||
|
||||
return m_should_cancel;
|
||||
}
|
||||
|
||||
void Updater::update_internal()
|
||||
{
|
||||
httplib::SSLClient cli(download_host, 443);
|
||||
cli.set_follow_location(true);
|
||||
auto res = cli.Get(download_uri, [this](uint64_t len, uint64_t total) {
|
||||
m_update_percentage = len*100/total;
|
||||
return !m_should_cancel;
|
||||
});
|
||||
g_autoptr(GByteArray) data = g_byte_array_new();
|
||||
|
||||
http_progress_cb_info progress_info;
|
||||
progress_info.userptr = this;
|
||||
progress_info.progress = [](http_progress_cb_info *info) {
|
||||
return static_cast<Updater *>(info->userptr)->progress_cb(info);
|
||||
};
|
||||
|
||||
int res = http_get(download_url, data, &progress_info, NULL);
|
||||
|
||||
if (m_should_cancel) {
|
||||
m_should_cancel = false;
|
||||
m_status = UPDATER_IDLE;
|
||||
return;
|
||||
} else if (!res || res->status != 200) {
|
||||
} else if (res != 200) {
|
||||
m_status = UPDATER_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
mz_zip_archive zip;
|
||||
mz_zip_zero_struct(&zip);
|
||||
if (!mz_zip_reader_init_mem(&zip, res->body.data(), res->body.size(), 0)) {
|
||||
if (!mz_zip_reader_init_mem(&zip, data->data, data->len, 0)) {
|
||||
DPRINTF("mz_zip_reader_init_mem failed\n");
|
||||
m_status = UPDATER_ERROR;
|
||||
return;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// xemu User Interface
|
||||
//
|
||||
// Copyright (C) 2020-2022 Matt Borgerson
|
||||
// Copyright (C) 2020-2025 Matt Borgerson
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
|
@ -25,6 +25,7 @@
|
|||
extern "C" {
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/thread.h"
|
||||
#include "qemu/http.h"
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
|
@ -53,6 +54,9 @@ private:
|
|||
UpdateStatus m_status;
|
||||
UpdaterCallback m_on_complete;
|
||||
|
||||
protected:
|
||||
int progress_cb(http_progress_cb_info *progress_info);
|
||||
|
||||
public:
|
||||
Updater();
|
||||
UpdateStatus get_status() { return m_status; }
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/*
|
||||
* Simple HTTP handlers
|
||||
*
|
||||
* Copyright (c) 2025 Matt Borgerson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/http.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
// Ignore SSL certificate verification (for self-signed certs)
|
||||
#define ALLOW_INSECURE_HOSTS 0
|
||||
|
||||
static bool libcurl_init_called = false;
|
||||
static bool libcurl_init_success = false;
|
||||
|
||||
static bool ensure_libcurl_initialized(Error **errp)
|
||||
{
|
||||
if (!libcurl_init_called) {
|
||||
CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
|
||||
libcurl_init_called = true;
|
||||
if (res == CURLE_OK) {
|
||||
libcurl_init_success = true;
|
||||
atexit(curl_global_cleanup);
|
||||
}
|
||||
}
|
||||
|
||||
if (!libcurl_init_success) {
|
||||
error_setg(errp, "curl_global_init failed");
|
||||
}
|
||||
|
||||
return libcurl_init_success;
|
||||
}
|
||||
|
||||
static int http_progress_cb(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
|
||||
curl_off_t ultotal, curl_off_t ulnow)
|
||||
{
|
||||
http_progress_cb_info *info = clientp;
|
||||
|
||||
info->dlnow = dlnow;
|
||||
info->dltotal = dltotal;
|
||||
|
||||
info->ulnow = ulnow;
|
||||
info->ultotal = ultotal;
|
||||
|
||||
return info->progress(info);
|
||||
}
|
||||
|
||||
static size_t http_get_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
assert(size == 1); // Per CURLOPT_WRITEFUNCTION spec
|
||||
if (userdata) {
|
||||
g_byte_array_append((GByteArray *)userdata, ptr, nmemb);
|
||||
}
|
||||
return nmemb;
|
||||
}
|
||||
|
||||
int http_get(const char *url, GByteArray *response_body,
|
||||
http_progress_cb_info *progress_info, Error **errp)
|
||||
{
|
||||
if (!ensure_libcurl_initialized(errp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
error_setg(errp, "curl_easy_init failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_get_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, response_body);
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // Follow redirects
|
||||
#if ALLOW_INSECURE_HOSTS
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
#endif
|
||||
if (progress_info) {
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, http_progress_cb);
|
||||
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, (void *)progress_info);
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
|
||||
}
|
||||
|
||||
long http_response_code = -1;
|
||||
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
if (res == CURLE_OK) {
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);
|
||||
} else {
|
||||
error_setg(errp, "curl_easy_perform failed with code %d", res);
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
return http_response_code;
|
||||
}
|
||||
|
||||
int http_post_json(const char *url, const char *json_data, Error **errp)
|
||||
{
|
||||
if (!ensure_libcurl_initialized(errp)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
error_setg(errp, "curl_easy_init failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct curl_slist *headers =
|
||||
curl_slist_append(NULL, "Content-Type: application/json");
|
||||
if (!headers) {
|
||||
error_setg(errp, "curl_slist_append failed");
|
||||
curl_easy_cleanup(curl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1L);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
#if ALLOW_INSECURE_HOSTS
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
#endif
|
||||
|
||||
long http_response_code = -1;
|
||||
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
if (res == CURLE_OK) {
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response_code);
|
||||
} else {
|
||||
error_setg(errp, "curl_easy_perform failed with code %d", res);
|
||||
}
|
||||
|
||||
curl_slist_free_all(headers);
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
return http_response_code;
|
||||
}
|
|
@ -136,3 +136,4 @@ elif cpu in ['riscv32', 'riscv64']
|
|||
util_ss.add(files('cpuinfo-riscv.c'))
|
||||
endif
|
||||
util_ss.add(files('sha1.c','rc4.c'))
|
||||
util_ss.add([curl, files('http.c')])
|
||||
|
|
Loading…
Reference in New Issue