Commit b37ce45d authored by Henri Verbeet's avatar Henri Verbeet Committed by Alexandre Julliard

wined3d: Move pixel shader constants to wined3d_state.

parent 33dfb953
...@@ -584,9 +584,9 @@ static inline void shader_arb_ps_local_constants(IWineD3DDeviceImpl* deviceImpl) ...@@ -584,9 +584,9 @@ static inline void shader_arb_ps_local_constants(IWineD3DDeviceImpl* deviceImpl)
if(gl_shader->int_consts[i] != WINED3D_CONST_NUM_UNUSED) if(gl_shader->int_consts[i] != WINED3D_CONST_NUM_UNUSED)
{ {
float val[4]; float val[4];
val[0] = (float) stateBlock->pixelShaderConstantI[4 * i]; val[0] = (float)stateBlock->state.ps_consts_i[4 * i];
val[1] = (float) stateBlock->pixelShaderConstantI[4 * i + 1]; val[1] = (float)stateBlock->state.ps_consts_i[4 * i + 1];
val[2] = (float) stateBlock->pixelShaderConstantI[4 * i + 2]; val[2] = (float)stateBlock->state.ps_consts_i[4 * i + 2];
val[3] = -1.0f; val[3] = -1.0f;
GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, gl_shader->int_consts[i], val)); GL_EXTCALL(glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, gl_shader->int_consts[i], val));
...@@ -656,7 +656,7 @@ static void shader_arb_load_constants(const struct wined3d_context *context, cha ...@@ -656,7 +656,7 @@ static void shader_arb_load_constants(const struct wined3d_context *context, cha
/* Load DirectX 9 float constants for pixel shader */ /* Load DirectX 9 float constants for pixel shader */
device->highest_dirty_ps_const = shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB, device->highest_dirty_ps_const = shader_arb_load_constantsF(pshader, gl_info, GL_FRAGMENT_PROGRAM_ARB,
device->highest_dirty_ps_const, stateBlock->pixelShaderConstantF, context->pshader_const_dirty); device->highest_dirty_ps_const, stateBlock->state.ps_consts_f, context->pshader_const_dirty);
shader_arb_ps_local_constants(device); shader_arb_ps_local_constants(device);
} }
} }
...@@ -4403,7 +4403,8 @@ static inline void find_arb_ps_compile_args(IWineD3DPixelShaderImpl *shader, IWi ...@@ -4403,7 +4403,8 @@ static inline void find_arb_ps_compile_args(IWineD3DPixelShaderImpl *shader, IWi
for(i = 0; i < MAX_CONST_B; i++) for(i = 0; i < MAX_CONST_B; i++)
{ {
if(stateblock->pixelShaderConstantB[i]) args->bools |= ( 1 << i); if (stateblock->state.ps_consts_b[i])
args->bools |= ( 1 << i);
} }
/* Only enable the clip plane emulation KIL if at least one clipplane is enabled. The KIL instruction /* Only enable the clip plane emulation KIL if at least one clipplane is enabled. The KIL instruction
...@@ -4435,9 +4436,9 @@ static inline void find_arb_ps_compile_args(IWineD3DPixelShaderImpl *shader, IWi ...@@ -4435,9 +4436,9 @@ static inline void find_arb_ps_compile_args(IWineD3DPixelShaderImpl *shader, IWi
} }
else else
{ {
args->loop_ctrl[i][0] = stateblock->pixelShaderConstantI[i * 4]; args->loop_ctrl[i][0] = stateblock->state.ps_consts_i[i * 4];
args->loop_ctrl[i][1] = stateblock->pixelShaderConstantI[i * 4 + 1]; args->loop_ctrl[i][1] = stateblock->state.ps_consts_i[i * 4 + 1];
args->loop_ctrl[i][2] = stateblock->pixelShaderConstantI[i * 4 + 2]; args->loop_ctrl[i][2] = stateblock->state.ps_consts_i[i * 4 + 2];
} }
} }
} }
......
...@@ -3653,7 +3653,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB( ...@@ -3653,7 +3653,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL; if (!srcData || start >= MAX_CONST_B) return WINED3DERR_INVALIDCALL;
memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL)); memcpy(&This->updateStateBlock->state.ps_consts_b[start], srcData, cnt * sizeof(BOOL));
for (i = 0; i < cnt; i++) for (i = 0; i < cnt; i++)
TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false"); TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
...@@ -3681,7 +3681,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB( ...@@ -3681,7 +3681,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
if (!dstData || cnt < 0) if (!dstData || cnt < 0)
return WINED3DERR_INVALIDCALL; return WINED3DERR_INVALIDCALL;
memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL)); memcpy(dstData, &This->stateBlock->state.ps_consts_b[start], cnt * sizeof(BOOL));
return WINED3D_OK; return WINED3D_OK;
} }
...@@ -3699,7 +3699,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI( ...@@ -3699,7 +3699,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL; if (!srcData || start >= MAX_CONST_I) return WINED3DERR_INVALIDCALL;
memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4); memcpy(&This->updateStateBlock->state.ps_consts_i[start * 4], srcData, cnt * sizeof(int) * 4);
for (i = 0; i < cnt; i++) for (i = 0; i < cnt; i++)
TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i, TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]); srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
...@@ -3728,7 +3728,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI( ...@@ -3728,7 +3728,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
if (!dstData || cnt < 0) if (!dstData || cnt < 0)
return WINED3DERR_INVALIDCALL; return WINED3DERR_INVALIDCALL;
memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4); memcpy(dstData, &This->stateBlock->state.ps_consts_i[start * 4], cnt * sizeof(int) * 4);
return WINED3D_OK; return WINED3D_OK;
} }
...@@ -3748,7 +3748,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF( ...@@ -3748,7 +3748,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF) if (!srcData || start + count > This->d3d_pshader_constantF || start > This->d3d_pshader_constantF)
return WINED3DERR_INVALIDCALL; return WINED3DERR_INVALIDCALL;
memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4); memcpy(&This->updateStateBlock->state.ps_consts_f[start * 4], srcData, count * sizeof(float) * 4);
if(TRACE_ON(d3d)) { if(TRACE_ON(d3d)) {
for (i = 0; i < count; i++) for (i = 0; i < count; i++)
TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i, TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
...@@ -3782,7 +3782,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF( ...@@ -3782,7 +3782,7 @@ static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
if (!dstData || cnt < 0) if (!dstData || cnt < 0)
return WINED3DERR_INVALIDCALL; return WINED3DERR_INVALIDCALL;
memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4); memcpy(dstData, &This->stateBlock->state.ps_consts_f[start * 4], cnt * sizeof(float) * 4);
return WINED3D_OK; return WINED3D_OK;
} }
......
...@@ -778,15 +778,15 @@ static void shader_glsl_load_constants(const struct wined3d_context *context, ...@@ -778,15 +778,15 @@ static void shader_glsl_load_constants(const struct wined3d_context *context,
IWineD3DBaseShaderImpl *pshader = (IWineD3DBaseShaderImpl *)stateBlock->state.pixel_shader; IWineD3DBaseShaderImpl *pshader = (IWineD3DBaseShaderImpl *)stateBlock->state.pixel_shader;
/* Load DirectX 9 float constants/uniforms for pixel shader */ /* Load DirectX 9 float constants/uniforms for pixel shader */
shader_glsl_load_constantsF(pshader, gl_info, stateBlock->pixelShaderConstantF, shader_glsl_load_constantsF(pshader, gl_info, stateBlock->state.ps_consts_f,
prog->puniformF_locations, &priv->pconst_heap, priv->stack, constant_version); prog->puniformF_locations, &priv->pconst_heap, priv->stack, constant_version);
/* Load DirectX 9 integer constants/uniforms for pixel shader */ /* Load DirectX 9 integer constants/uniforms for pixel shader */
shader_glsl_load_constantsI(pshader, gl_info, prog->puniformI_locations, stateBlock->pixelShaderConstantI, shader_glsl_load_constantsI(pshader, gl_info, prog->puniformI_locations, stateBlock->state.ps_consts_i,
stateBlock->changed.pixelShaderConstantsI & pshader->baseShader.reg_maps.integer_constants); stateBlock->changed.pixelShaderConstantsI & pshader->baseShader.reg_maps.integer_constants);
/* Load DirectX 9 boolean constants/uniforms for pixel shader */ /* Load DirectX 9 boolean constants/uniforms for pixel shader */
shader_glsl_load_constantsB(pshader, gl_info, programId, stateBlock->pixelShaderConstantB, shader_glsl_load_constantsB(pshader, gl_info, programId, stateBlock->state.ps_consts_b,
stateBlock->changed.pixelShaderConstantsB & pshader->baseShader.reg_maps.boolean_constants); stateBlock->changed.pixelShaderConstantsB & pshader->baseShader.reg_maps.boolean_constants);
/* Upload the environment bump map matrix if needed. The needsbumpmat member specifies the texture stage to load the matrix from. /* Upload the environment bump map matrix if needed. The needsbumpmat member specifies the texture stage to load the matrix from.
......
...@@ -196,9 +196,9 @@ static HRESULT stateblock_allocate_shader_constants(IWineD3DStateBlockImpl *obje ...@@ -196,9 +196,9 @@ static HRESULT stateblock_allocate_shader_constants(IWineD3DStateBlockImpl *obje
IWineD3DDeviceImpl *device = object->device; IWineD3DDeviceImpl *device = object->device;
/* Allocate space for floating point constants */ /* Allocate space for floating point constants */
object->pixelShaderConstantF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->state.ps_consts_f = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(float) * device->d3d_pshader_constantF * 4); sizeof(float) * device->d3d_pshader_constantF * 4);
if (!object->pixelShaderConstantF) goto fail; if (!object->state.ps_consts_f) goto fail;
object->changed.pixelShaderConstantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->changed.pixelShaderConstantsF = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(BOOL) * device->d3d_pshader_constantF); sizeof(BOOL) * device->d3d_pshader_constantF);
...@@ -224,7 +224,7 @@ static HRESULT stateblock_allocate_shader_constants(IWineD3DStateBlockImpl *obje ...@@ -224,7 +224,7 @@ static HRESULT stateblock_allocate_shader_constants(IWineD3DStateBlockImpl *obje
fail: fail:
ERR("Failed to allocate memory\n"); ERR("Failed to allocate memory\n");
HeapFree(GetProcessHeap(), 0, object->pixelShaderConstantF); HeapFree(GetProcessHeap(), 0, object->state.ps_consts_f);
HeapFree(GetProcessHeap(), 0, object->changed.pixelShaderConstantsF); HeapFree(GetProcessHeap(), 0, object->changed.pixelShaderConstantsF);
HeapFree(GetProcessHeap(), 0, object->state.vs_consts_f); HeapFree(GetProcessHeap(), 0, object->state.vs_consts_f);
HeapFree(GetProcessHeap(), 0, object->changed.vertexShaderConstantsF); HeapFree(GetProcessHeap(), 0, object->changed.vertexShaderConstantsF);
...@@ -528,7 +528,7 @@ static ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) { ...@@ -528,7 +528,7 @@ static ULONG WINAPI IWineD3DStateBlockImpl_Release(IWineD3DStateBlock *iface) {
HeapFree(GetProcessHeap(), 0, This->state.vs_consts_f); HeapFree(GetProcessHeap(), 0, This->state.vs_consts_f);
HeapFree(GetProcessHeap(), 0, This->changed.vertexShaderConstantsF); HeapFree(GetProcessHeap(), 0, This->changed.vertexShaderConstantsF);
HeapFree(GetProcessHeap(), 0, This->pixelShaderConstantF); HeapFree(GetProcessHeap(), 0, This->state.ps_consts_f);
HeapFree(GetProcessHeap(), 0, This->changed.pixelShaderConstantsF); HeapFree(GetProcessHeap(), 0, This->changed.pixelShaderConstantsF);
HeapFree(GetProcessHeap(), 0, This->contained_vs_consts_f); HeapFree(GetProcessHeap(), 0, This->contained_vs_consts_f);
HeapFree(GetProcessHeap(), 0, This->contained_ps_consts_f); HeapFree(GetProcessHeap(), 0, This->contained_ps_consts_f);
...@@ -670,15 +670,15 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) ...@@ -670,15 +670,15 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
TRACE("Setting %p from %p %u to {%.8e, %.8e, %.8e, %.8e}.\n", TRACE("Setting %p from %p %u to {%.8e, %.8e, %.8e, %.8e}.\n",
This, targetStateBlock, idx, This, targetStateBlock, idx,
targetStateBlock->pixelShaderConstantF[idx * 4 + 0], targetStateBlock->state.ps_consts_f[idx * 4 + 0],
targetStateBlock->pixelShaderConstantF[idx * 4 + 1], targetStateBlock->state.ps_consts_f[idx * 4 + 1],
targetStateBlock->pixelShaderConstantF[idx * 4 + 2], targetStateBlock->state.ps_consts_f[idx * 4 + 2],
targetStateBlock->pixelShaderConstantF[idx * 4 + 3]); targetStateBlock->state.ps_consts_f[idx * 4 + 3]);
This->pixelShaderConstantF[idx * 4 + 0] = targetStateBlock->pixelShaderConstantF[idx * 4 + 0]; This->state.ps_consts_f[idx * 4 + 0] = targetStateBlock->state.ps_consts_f[idx * 4 + 0];
This->pixelShaderConstantF[idx * 4 + 1] = targetStateBlock->pixelShaderConstantF[idx * 4 + 1]; This->state.ps_consts_f[idx * 4 + 1] = targetStateBlock->state.ps_consts_f[idx * 4 + 1];
This->pixelShaderConstantF[idx * 4 + 2] = targetStateBlock->pixelShaderConstantF[idx * 4 + 2]; This->state.ps_consts_f[idx * 4 + 2] = targetStateBlock->state.ps_consts_f[idx * 4 + 2];
This->pixelShaderConstantF[idx * 4 + 3] = targetStateBlock->pixelShaderConstantF[idx * 4 + 3]; This->state.ps_consts_f[idx * 4 + 3] = targetStateBlock->state.ps_consts_f[idx * 4 + 3];
} }
/* Pixel Shader Integer Constants */ /* Pixel Shader Integer Constants */
...@@ -687,15 +687,15 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) ...@@ -687,15 +687,15 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
unsigned int idx = This->contained_ps_consts_i[i]; unsigned int idx = This->contained_ps_consts_i[i];
TRACE("Setting %p from %p %u to {%d, %d, %d, %d}.\n", TRACE("Setting %p from %p %u to {%d, %d, %d, %d}.\n",
This, targetStateBlock, idx, This, targetStateBlock, idx,
targetStateBlock->pixelShaderConstantI[idx * 4 + 0], targetStateBlock->state.ps_consts_i[idx * 4 + 0],
targetStateBlock->pixelShaderConstantI[idx * 4 + 1], targetStateBlock->state.ps_consts_i[idx * 4 + 1],
targetStateBlock->pixelShaderConstantI[idx * 4 + 2], targetStateBlock->state.ps_consts_i[idx * 4 + 2],
targetStateBlock->pixelShaderConstantI[idx * 4 + 3]); targetStateBlock->state.ps_consts_i[idx * 4 + 3]);
This->pixelShaderConstantI[idx * 4 + 0] = targetStateBlock->pixelShaderConstantI[idx * 4 + 0]; This->state.ps_consts_i[idx * 4 + 0] = targetStateBlock->state.ps_consts_i[idx * 4 + 0];
This->pixelShaderConstantI[idx * 4 + 1] = targetStateBlock->pixelShaderConstantI[idx * 4 + 1]; This->state.ps_consts_i[idx * 4 + 1] = targetStateBlock->state.ps_consts_i[idx * 4 + 1];
This->pixelShaderConstantI[idx * 4 + 2] = targetStateBlock->pixelShaderConstantI[idx * 4 + 2]; This->state.ps_consts_i[idx * 4 + 2] = targetStateBlock->state.ps_consts_i[idx * 4 + 2];
This->pixelShaderConstantI[idx * 4 + 3] = targetStateBlock->pixelShaderConstantI[idx * 4 + 3]; This->state.ps_consts_i[idx * 4 + 3] = targetStateBlock->state.ps_consts_i[idx * 4 + 3];
} }
/* Pixel Shader Boolean Constants */ /* Pixel Shader Boolean Constants */
...@@ -703,9 +703,9 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface) ...@@ -703,9 +703,9 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Capture(IWineD3DStateBlock *iface)
{ {
unsigned int idx = This->contained_ps_consts_b[i]; unsigned int idx = This->contained_ps_consts_b[i];
TRACE("Setting %p from %p %u to %s.\n", This, targetStateBlock, idx, TRACE("Setting %p from %p %u to %s.\n", This, targetStateBlock, idx,
targetStateBlock->pixelShaderConstantB[idx] ? "TRUE" : "FALSE"); targetStateBlock->state.ps_consts_b[idx] ? "TRUE" : "FALSE");
This->pixelShaderConstantB[idx] = targetStateBlock->pixelShaderConstantB[idx]; This->state.ps_consts_b[idx] = targetStateBlock->state.ps_consts_b[idx];
} }
/* Others + Render & Texture */ /* Others + Render & Texture */
...@@ -943,17 +943,17 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Apply(IWineD3DStateBlock *iface) ...@@ -943,17 +943,17 @@ static HRESULT WINAPI IWineD3DStateBlockImpl_Apply(IWineD3DStateBlock *iface)
for (i = 0; i < This->num_contained_ps_consts_f; ++i) for (i = 0; i < This->num_contained_ps_consts_f; ++i)
{ {
IWineD3DDevice_SetPixelShaderConstantF(device, This->contained_ps_consts_f[i], IWineD3DDevice_SetPixelShaderConstantF(device, This->contained_ps_consts_f[i],
This->pixelShaderConstantF + This->contained_ps_consts_f[i] * 4, 1); This->state.ps_consts_f + This->contained_ps_consts_f[i] * 4, 1);
} }
for (i = 0; i < This->num_contained_ps_consts_i; ++i) for (i = 0; i < This->num_contained_ps_consts_i; ++i)
{ {
IWineD3DDevice_SetPixelShaderConstantI(device, This->contained_ps_consts_i[i], IWineD3DDevice_SetPixelShaderConstantI(device, This->contained_ps_consts_i[i],
This->pixelShaderConstantI + This->contained_ps_consts_i[i] * 4, 1); This->state.ps_consts_i + This->contained_ps_consts_i[i] * 4, 1);
} }
for (i = 0; i < This->num_contained_ps_consts_b; ++i) for (i = 0; i < This->num_contained_ps_consts_b; ++i)
{ {
IWineD3DDevice_SetPixelShaderConstantB(device, This->contained_ps_consts_b[i], IWineD3DDevice_SetPixelShaderConstantB(device, This->contained_ps_consts_b[i],
This->pixelShaderConstantB + This->contained_ps_consts_b[i], 1); This->state.ps_consts_b + This->contained_ps_consts_b[i], 1);
} }
/* Render */ /* Render */
......
...@@ -2357,6 +2357,9 @@ struct wined3d_state ...@@ -2357,6 +2357,9 @@ struct wined3d_state
float *vs_consts_f; float *vs_consts_f;
struct IWineD3DPixelShaderImpl *pixel_shader; struct IWineD3DPixelShaderImpl *pixel_shader;
BOOL ps_consts_b[MAX_CONST_B];
INT ps_consts_i[MAX_CONST_I * 4];
float *ps_consts_f;
IWineD3DBaseTextureImpl *textures[MAX_COMBINED_SAMPLERS]; IWineD3DBaseTextureImpl *textures[MAX_COMBINED_SAMPLERS];
DWORD sampler_states[MAX_COMBINED_SAMPLERS][WINED3D_HIGHEST_SAMPLER_STATE + 1]; DWORD sampler_states[MAX_COMBINED_SAMPLERS][WINED3D_HIGHEST_SAMPLER_STATE + 1];
...@@ -2408,11 +2411,6 @@ struct IWineD3DStateBlockImpl ...@@ -2408,11 +2411,6 @@ struct IWineD3DStateBlockImpl
double clipplane[MAX_CLIPPLANES][4]; double clipplane[MAX_CLIPPLANES][4];
WINED3DCLIPSTATUS clip_status; WINED3DCLIPSTATUS clip_status;
/* Pixel Shader Constants */
BOOL pixelShaderConstantB[MAX_CONST_B];
INT pixelShaderConstantI[MAX_CONST_I * 4];
float *pixelShaderConstantF;
/* Contained state management */ /* Contained state management */
DWORD contained_render_states[WINEHIGHEST_RENDER_STATE + 1]; DWORD contained_render_states[WINEHIGHEST_RENDER_STATE + 1];
unsigned int num_contained_render_states; unsigned int num_contained_render_states;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment