mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 18:39:59 +00:00
drm/i915: Unify engine init loop
With the unified common engine setup done, and the execlist engine initialization loop clearly split into two phases, we can eliminate the separate legacy engine initialization code. v2: Fix cleanup path for legacy. v3: Rename constructors. (Chris Wilson) Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Reviewed-by: Chris Wilson <chris-wilson.co.uk>
This commit is contained in:
parent
bb45438f5e
commit
8b3e2d3639
6 changed files with 50 additions and 105 deletions
|
@ -2016,7 +2016,6 @@ struct drm_i915_private {
|
||||||
int (*execbuf_submit)(struct i915_execbuffer_params *params,
|
int (*execbuf_submit)(struct i915_execbuffer_params *params,
|
||||||
struct drm_i915_gem_execbuffer2 *args,
|
struct drm_i915_gem_execbuffer2 *args,
|
||||||
struct list_head *vmas);
|
struct list_head *vmas);
|
||||||
int (*init_engines)(struct drm_device *dev);
|
|
||||||
void (*cleanup_engine)(struct intel_engine_cs *engine);
|
void (*cleanup_engine)(struct intel_engine_cs *engine);
|
||||||
void (*stop_engine)(struct intel_engine_cs *engine);
|
void (*stop_engine)(struct intel_engine_cs *engine);
|
||||||
|
|
||||||
|
@ -3374,7 +3373,6 @@ static inline u32 i915_reset_count(struct i915_gpu_error *error)
|
||||||
void i915_gem_reset(struct drm_device *dev);
|
void i915_gem_reset(struct drm_device *dev);
|
||||||
bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
|
bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
|
||||||
int __must_check i915_gem_init(struct drm_device *dev);
|
int __must_check i915_gem_init(struct drm_device *dev);
|
||||||
int i915_gem_init_engines(struct drm_device *dev);
|
|
||||||
int __must_check i915_gem_init_hw(struct drm_device *dev);
|
int __must_check i915_gem_init_hw(struct drm_device *dev);
|
||||||
void i915_gem_init_swizzling(struct drm_device *dev);
|
void i915_gem_init_swizzling(struct drm_device *dev);
|
||||||
void i915_gem_cleanup_engines(struct drm_device *dev);
|
void i915_gem_cleanup_engines(struct drm_device *dev);
|
||||||
|
|
|
@ -5056,53 +5056,6 @@ static void init_unused_rings(struct drm_device *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int i915_gem_init_engines(struct drm_device *dev)
|
|
||||||
{
|
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = intel_init_render_ring_buffer(dev);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (HAS_BSD(dev)) {
|
|
||||||
ret = intel_init_bsd_ring_buffer(dev);
|
|
||||||
if (ret)
|
|
||||||
goto cleanup_render_ring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HAS_BLT(dev)) {
|
|
||||||
ret = intel_init_blt_ring_buffer(dev);
|
|
||||||
if (ret)
|
|
||||||
goto cleanup_bsd_ring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HAS_VEBOX(dev)) {
|
|
||||||
ret = intel_init_vebox_ring_buffer(dev);
|
|
||||||
if (ret)
|
|
||||||
goto cleanup_blt_ring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HAS_BSD2(dev)) {
|
|
||||||
ret = intel_init_bsd2_ring_buffer(dev);
|
|
||||||
if (ret)
|
|
||||||
goto cleanup_vebox_ring;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
cleanup_vebox_ring:
|
|
||||||
intel_cleanup_engine(&dev_priv->engine[VECS]);
|
|
||||||
cleanup_blt_ring:
|
|
||||||
intel_cleanup_engine(&dev_priv->engine[BCS]);
|
|
||||||
cleanup_bsd_ring:
|
|
||||||
intel_cleanup_engine(&dev_priv->engine[VCS]);
|
|
||||||
cleanup_render_ring:
|
|
||||||
intel_cleanup_engine(&dev_priv->engine[RCS]);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
i915_gem_init_hw(struct drm_device *dev)
|
i915_gem_init_hw(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
|
@ -5178,12 +5131,10 @@ int i915_gem_init(struct drm_device *dev)
|
||||||
|
|
||||||
if (!i915.enable_execlists) {
|
if (!i915.enable_execlists) {
|
||||||
dev_priv->gt.execbuf_submit = i915_gem_ringbuffer_submission;
|
dev_priv->gt.execbuf_submit = i915_gem_ringbuffer_submission;
|
||||||
dev_priv->gt.init_engines = i915_gem_init_engines;
|
|
||||||
dev_priv->gt.cleanup_engine = intel_cleanup_engine;
|
dev_priv->gt.cleanup_engine = intel_cleanup_engine;
|
||||||
dev_priv->gt.stop_engine = intel_stop_engine;
|
dev_priv->gt.stop_engine = intel_stop_engine;
|
||||||
} else {
|
} else {
|
||||||
dev_priv->gt.execbuf_submit = intel_execlists_submission;
|
dev_priv->gt.execbuf_submit = intel_execlists_submission;
|
||||||
dev_priv->gt.init_engines = intel_logical_rings_init;
|
|
||||||
dev_priv->gt.cleanup_engine = intel_logical_ring_cleanup;
|
dev_priv->gt.cleanup_engine = intel_logical_ring_cleanup;
|
||||||
dev_priv->gt.stop_engine = intel_logical_ring_stop;
|
dev_priv->gt.stop_engine = intel_logical_ring_stop;
|
||||||
}
|
}
|
||||||
|
@ -5203,7 +5154,7 @@ int i915_gem_init(struct drm_device *dev)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
ret = dev_priv->gt.init_engines(dev);
|
ret = intel_engines_init(dev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
|
|
|
@ -2139,7 +2139,8 @@ static const struct engine_info {
|
||||||
unsigned guc_id;
|
unsigned guc_id;
|
||||||
u32 mmio_base;
|
u32 mmio_base;
|
||||||
unsigned irq_shift;
|
unsigned irq_shift;
|
||||||
int (*init)(struct intel_engine_cs *engine);
|
int (*init_legacy)(struct intel_engine_cs *engine);
|
||||||
|
int (*init_execlists)(struct intel_engine_cs *engine);
|
||||||
} intel_engines[] = {
|
} intel_engines[] = {
|
||||||
[RCS] = {
|
[RCS] = {
|
||||||
.name = "render ring",
|
.name = "render ring",
|
||||||
|
@ -2147,7 +2148,8 @@ static const struct engine_info {
|
||||||
.guc_id = GUC_RENDER_ENGINE,
|
.guc_id = GUC_RENDER_ENGINE,
|
||||||
.mmio_base = RENDER_RING_BASE,
|
.mmio_base = RENDER_RING_BASE,
|
||||||
.irq_shift = GEN8_RCS_IRQ_SHIFT,
|
.irq_shift = GEN8_RCS_IRQ_SHIFT,
|
||||||
.init = logical_render_ring_init,
|
.init_execlists = logical_render_ring_init,
|
||||||
|
.init_legacy = intel_init_render_ring_buffer,
|
||||||
},
|
},
|
||||||
[BCS] = {
|
[BCS] = {
|
||||||
.name = "blitter ring",
|
.name = "blitter ring",
|
||||||
|
@ -2155,7 +2157,8 @@ static const struct engine_info {
|
||||||
.guc_id = GUC_BLITTER_ENGINE,
|
.guc_id = GUC_BLITTER_ENGINE,
|
||||||
.mmio_base = BLT_RING_BASE,
|
.mmio_base = BLT_RING_BASE,
|
||||||
.irq_shift = GEN8_BCS_IRQ_SHIFT,
|
.irq_shift = GEN8_BCS_IRQ_SHIFT,
|
||||||
.init = logical_xcs_ring_init,
|
.init_execlists = logical_xcs_ring_init,
|
||||||
|
.init_legacy = intel_init_blt_ring_buffer,
|
||||||
},
|
},
|
||||||
[VCS] = {
|
[VCS] = {
|
||||||
.name = "bsd ring",
|
.name = "bsd ring",
|
||||||
|
@ -2163,7 +2166,8 @@ static const struct engine_info {
|
||||||
.guc_id = GUC_VIDEO_ENGINE,
|
.guc_id = GUC_VIDEO_ENGINE,
|
||||||
.mmio_base = GEN6_BSD_RING_BASE,
|
.mmio_base = GEN6_BSD_RING_BASE,
|
||||||
.irq_shift = GEN8_VCS1_IRQ_SHIFT,
|
.irq_shift = GEN8_VCS1_IRQ_SHIFT,
|
||||||
.init = logical_xcs_ring_init,
|
.init_execlists = logical_xcs_ring_init,
|
||||||
|
.init_legacy = intel_init_bsd_ring_buffer,
|
||||||
},
|
},
|
||||||
[VCS2] = {
|
[VCS2] = {
|
||||||
.name = "bsd2 ring",
|
.name = "bsd2 ring",
|
||||||
|
@ -2171,7 +2175,8 @@ static const struct engine_info {
|
||||||
.guc_id = GUC_VIDEO_ENGINE2,
|
.guc_id = GUC_VIDEO_ENGINE2,
|
||||||
.mmio_base = GEN8_BSD2_RING_BASE,
|
.mmio_base = GEN8_BSD2_RING_BASE,
|
||||||
.irq_shift = GEN8_VCS2_IRQ_SHIFT,
|
.irq_shift = GEN8_VCS2_IRQ_SHIFT,
|
||||||
.init = logical_xcs_ring_init,
|
.init_execlists = logical_xcs_ring_init,
|
||||||
|
.init_legacy = intel_init_bsd2_ring_buffer,
|
||||||
},
|
},
|
||||||
[VECS] = {
|
[VECS] = {
|
||||||
.name = "video enhancement ring",
|
.name = "video enhancement ring",
|
||||||
|
@ -2179,7 +2184,8 @@ static const struct engine_info {
|
||||||
.guc_id = GUC_VIDEOENHANCE_ENGINE,
|
.guc_id = GUC_VIDEOENHANCE_ENGINE,
|
||||||
.mmio_base = VEBOX_RING_BASE,
|
.mmio_base = VEBOX_RING_BASE,
|
||||||
.irq_shift = GEN8_VECS_IRQ_SHIFT,
|
.irq_shift = GEN8_VECS_IRQ_SHIFT,
|
||||||
.init = logical_xcs_ring_init,
|
.init_execlists = logical_xcs_ring_init,
|
||||||
|
.init_legacy = intel_init_vebox_ring_buffer,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2202,20 +2208,16 @@ intel_engine_setup(struct drm_i915_private *dev_priv,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* intel_logical_rings_init() - allocate, populate and init the Engine Command Streamers
|
* intel_engines_init() - allocate, populate and init the Engine Command Streamers
|
||||||
* @dev: DRM device.
|
* @dev: DRM device.
|
||||||
*
|
*
|
||||||
* This function inits the engines for an Execlists submission style (the
|
|
||||||
* equivalent in the legacy ringbuffer submission world would be
|
|
||||||
* i915_gem_init_engines). It does it only for those engines that are present in
|
|
||||||
* the hardware.
|
|
||||||
*
|
|
||||||
* Return: non-zero if the initialization failed.
|
* Return: non-zero if the initialization failed.
|
||||||
*/
|
*/
|
||||||
int intel_logical_rings_init(struct drm_device *dev)
|
int intel_engines_init(struct drm_device *dev)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = to_i915(dev);
|
||||||
unsigned int mask = 0;
|
unsigned int mask = 0;
|
||||||
|
int (*init)(struct intel_engine_cs *engine);
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -2226,10 +2228,15 @@ int intel_logical_rings_init(struct drm_device *dev)
|
||||||
if (!HAS_ENGINE(dev_priv, i))
|
if (!HAS_ENGINE(dev_priv, i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!intel_engines[i].init)
|
if (i915.enable_execlists)
|
||||||
|
init = intel_engines[i].init_execlists;
|
||||||
|
else
|
||||||
|
init = intel_engines[i].init_legacy;
|
||||||
|
|
||||||
|
if (!init)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = intel_engines[i].init(intel_engine_setup(dev_priv, i));
|
ret = init(intel_engine_setup(dev_priv, i));
|
||||||
if (ret)
|
if (ret)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
@ -2250,8 +2257,12 @@ int intel_logical_rings_init(struct drm_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
for (i = 0; i < I915_NUM_ENGINES; i++)
|
for (i = 0; i < I915_NUM_ENGINES; i++) {
|
||||||
intel_logical_ring_cleanup(&dev_priv->engine[i]);
|
if (i915.enable_execlists)
|
||||||
|
intel_logical_ring_cleanup(&dev_priv->engine[i]);
|
||||||
|
else
|
||||||
|
intel_cleanup_engine(&dev_priv->engine[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request
|
||||||
int intel_logical_ring_reserve_space(struct drm_i915_gem_request *request);
|
int intel_logical_ring_reserve_space(struct drm_i915_gem_request *request);
|
||||||
void intel_logical_ring_stop(struct intel_engine_cs *engine);
|
void intel_logical_ring_stop(struct intel_engine_cs *engine);
|
||||||
void intel_logical_ring_cleanup(struct intel_engine_cs *engine);
|
void intel_logical_ring_cleanup(struct intel_engine_cs *engine);
|
||||||
int intel_logical_rings_init(struct drm_device *dev);
|
int intel_engines_init(struct drm_device *dev);
|
||||||
|
|
||||||
int logical_ring_flush_all_caches(struct drm_i915_gem_request *req);
|
int logical_ring_flush_all_caches(struct drm_i915_gem_request *req);
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2836,14 +2836,11 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv,
|
||||||
intel_ring_init_semaphores(dev_priv, engine);
|
intel_ring_init_semaphores(dev_priv, engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
int intel_init_render_ring_buffer(struct drm_device *dev)
|
int intel_init_render_ring_buffer(struct intel_engine_cs *engine)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = engine->i915;
|
||||||
struct intel_engine_cs *engine;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
engine = intel_engine_setup(dev_priv, RCS);
|
|
||||||
|
|
||||||
intel_ring_default_vfuncs(dev_priv, engine);
|
intel_ring_default_vfuncs(dev_priv, engine);
|
||||||
|
|
||||||
engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
|
engine->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
|
||||||
|
@ -2877,7 +2874,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
|
||||||
engine->init_hw = init_render_ring;
|
engine->init_hw = init_render_ring;
|
||||||
engine->cleanup = render_ring_cleanup;
|
engine->cleanup = render_ring_cleanup;
|
||||||
|
|
||||||
ret = intel_init_ring_buffer(dev, engine);
|
ret = intel_init_ring_buffer(&dev_priv->drm, engine);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
@ -2894,12 +2891,9 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int intel_init_bsd_ring_buffer(struct drm_device *dev)
|
int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = engine->i915;
|
||||||
struct intel_engine_cs *engine;
|
|
||||||
|
|
||||||
engine = intel_engine_setup(dev_priv, VCS);
|
|
||||||
|
|
||||||
intel_ring_default_vfuncs(dev_priv, engine);
|
intel_ring_default_vfuncs(dev_priv, engine);
|
||||||
|
|
||||||
|
@ -2922,18 +2916,15 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
|
||||||
engine->irq_enable_mask = I915_BSD_USER_INTERRUPT;
|
engine->irq_enable_mask = I915_BSD_USER_INTERRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return intel_init_ring_buffer(dev, engine);
|
return intel_init_ring_buffer(&dev_priv->drm, engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the second BSD ring (eg. Broadwell GT3, Skylake GT3)
|
* Initialize the second BSD ring (eg. Broadwell GT3, Skylake GT3)
|
||||||
*/
|
*/
|
||||||
int intel_init_bsd2_ring_buffer(struct drm_device *dev)
|
int intel_init_bsd2_ring_buffer(struct intel_engine_cs *engine)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = engine->i915;
|
||||||
struct intel_engine_cs *engine;
|
|
||||||
|
|
||||||
engine = intel_engine_setup(dev_priv, VCS2);
|
|
||||||
|
|
||||||
intel_ring_default_vfuncs(dev_priv, engine);
|
intel_ring_default_vfuncs(dev_priv, engine);
|
||||||
|
|
||||||
|
@ -2941,15 +2932,12 @@ int intel_init_bsd2_ring_buffer(struct drm_device *dev)
|
||||||
engine->irq_enable_mask =
|
engine->irq_enable_mask =
|
||||||
GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
|
GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
|
||||||
|
|
||||||
return intel_init_ring_buffer(dev, engine);
|
return intel_init_ring_buffer(&dev_priv->drm, engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
int intel_init_blt_ring_buffer(struct drm_device *dev)
|
int intel_init_blt_ring_buffer(struct intel_engine_cs *engine)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = engine->i915;
|
||||||
struct intel_engine_cs *engine;
|
|
||||||
|
|
||||||
engine = intel_engine_setup(dev_priv, BCS);
|
|
||||||
|
|
||||||
intel_ring_default_vfuncs(dev_priv, engine);
|
intel_ring_default_vfuncs(dev_priv, engine);
|
||||||
|
|
||||||
|
@ -2960,15 +2948,12 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
|
||||||
else
|
else
|
||||||
engine->irq_enable_mask = GT_BLT_USER_INTERRUPT;
|
engine->irq_enable_mask = GT_BLT_USER_INTERRUPT;
|
||||||
|
|
||||||
return intel_init_ring_buffer(dev, engine);
|
return intel_init_ring_buffer(&dev_priv->drm, engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
int intel_init_vebox_ring_buffer(struct drm_device *dev)
|
int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine)
|
||||||
{
|
{
|
||||||
struct drm_i915_private *dev_priv = to_i915(dev);
|
struct drm_i915_private *dev_priv = engine->i915;
|
||||||
struct intel_engine_cs *engine;
|
|
||||||
|
|
||||||
engine = intel_engine_setup(dev_priv, VECS);
|
|
||||||
|
|
||||||
intel_ring_default_vfuncs(dev_priv, engine);
|
intel_ring_default_vfuncs(dev_priv, engine);
|
||||||
|
|
||||||
|
@ -2983,7 +2968,7 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev)
|
||||||
engine->irq_disable = hsw_vebox_irq_disable;
|
engine->irq_disable = hsw_vebox_irq_disable;
|
||||||
}
|
}
|
||||||
|
|
||||||
return intel_init_ring_buffer(dev, engine);
|
return intel_init_ring_buffer(&dev_priv->drm, engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -484,11 +484,11 @@ int intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req);
|
||||||
int intel_init_pipe_control(struct intel_engine_cs *engine, int size);
|
int intel_init_pipe_control(struct intel_engine_cs *engine, int size);
|
||||||
void intel_fini_pipe_control(struct intel_engine_cs *engine);
|
void intel_fini_pipe_control(struct intel_engine_cs *engine);
|
||||||
|
|
||||||
int intel_init_render_ring_buffer(struct drm_device *dev);
|
int intel_init_render_ring_buffer(struct intel_engine_cs *engine);
|
||||||
int intel_init_bsd_ring_buffer(struct drm_device *dev);
|
int intel_init_bsd_ring_buffer(struct intel_engine_cs *engine);
|
||||||
int intel_init_bsd2_ring_buffer(struct drm_device *dev);
|
int intel_init_bsd2_ring_buffer(struct intel_engine_cs *engine);
|
||||||
int intel_init_blt_ring_buffer(struct drm_device *dev);
|
int intel_init_blt_ring_buffer(struct intel_engine_cs *engine);
|
||||||
int intel_init_vebox_ring_buffer(struct drm_device *dev);
|
int intel_init_vebox_ring_buffer(struct intel_engine_cs *engine);
|
||||||
|
|
||||||
u64 intel_ring_get_active_head(struct intel_engine_cs *engine);
|
u64 intel_ring_get_active_head(struct intel_engine_cs *engine);
|
||||||
static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine)
|
static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine)
|
||||||
|
|
Loading…
Reference in a new issue