summaryrefslogtreecommitdiffstats
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
* i965/gs: implement EndPrimitive() functionality in the visitor.Paul Berry2013-09-112-1/+241
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | According to GLSL, the shader may call EndPrimitive() at any point during its execution, causing the line or triangle strip currently being output to be terminated and a new strip to be begun. This is implemented in gen7 hardware by using one control data bit per vertex, to indicate whether EndPrimitive() was called after that vertex was emitted. In order to make this work without sacrificing too much efficiency, we accumulate 32 control data bits at a time in a GRF. When we have accumulated 32 bits (or when the shader terminates), we output them to the appropriate DWORD in the control data header and reset the accumulator to 0. We have to take special care to make sure that EndPrimitive() calls that occur prior to the first vertex have no effect. Since geometry shaders that output a large number of vertices are likely to be rare, an optimization kicks in if max_vertices <= 32. In this case, we know that we can wait until the end of shader execution before any control data bits need to be output. I've tried to write the code in such a way that in the future, we can easily adapt it to output stream ID bits (which are two bits/vertex instead of one). Fixes piglit tests "spec/glsl-1.50/glsl-1.50-geometry-end-primitive *". Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* i965/vec4: Add the ability to emit opcodes with just a dst register.Paul Berry2013-09-112-0/+8
| | | | | | | This is needed for GS_OPCODE_PREPARE_CHANNEL_MASKS. Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* i965/gs: Add opcodes needed for EndPrimitive().Paul Berry2013-09-114-0/+120
| | | | | Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* i965/gen7: Add the ability to send URB_WRITE_OWORD messages.Paul Berry2013-09-113-2/+16
| | | | | | | | | | | | | | | Previously, brw_urb_WRITE() would always generate a URB_WRITE_HWORD message, we always wanted to write data to the URB in pairs of varying slots or larger (an HWORD is 32 bytes, which is 2 varying slots). In order to support geometry shader EndPrimitive functionality, we'll need the ability to write to just a single OWORD (16 byte) slot, since we'll only be outputting 32 of the control data bits at a time. So this patch adds a flag that will cause brw_urb_WRITE to generate a URB_WRITE_OWORD message. Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* i965/gen7: Allow URB_WRITE channel masks to be used.Paul Berry2013-09-112-1/+7
| | | | | | | | | | | | | | Previously, brw_urb_WRITE() would unconditionally override the channel masks in the URB_WRITE message to 0xff (indicating that all channels should be written to the URB). In order to support geometry shader EndPrimitive functionality, we'll need the ability to set the channel masks programatically, so that we can output just 32 of the control data bits at a time. So this patch adds a flag that will prevent brw_urb_WRITE() from overriding them. Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* i965/gs: Set control data header size/format appropriately for EndPrimitive().Paul Berry2013-09-117-15/+84
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The gen7 geometry shader uses a "control data header" at the beginning of the output URB entry to store either (a) flag bits (1 bit/vertex) indicating whether EndPrimitive() was called after each vertex, or (b) stream ID bits (2 bits/vertex) indicating which stream each vertex should be sent to (when multiple transform feedback streams are in use). Fortunately, OpenGL only requires separate streams to be supported when the output type is points, and EndPrimitive() only has an effect when the output type is line_strip or triangle_strip, so it's not a problem that these two uses of the control data header are mutually exclusive. This patch modifies do_vec4_gs_prog() to determine the correct hardware settings for configuring the control data header, and modifies upload_gs_state() to propagate these settings to the hardware. In addition, it modifies do_vec4_gs_prog() to ensure that the output URB entry is large enough to contain both the output vertices *and* the control data header. Finally, it modifies vec4_gs_visitor so that it accounts for the size of the control data header when computing the offset within the URB where output vertex data should be stored. Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> v2: Fixed incorrect handling of IVB/HSW differences. Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* glsl: During linking, record whether a GS uses EndPrimitive().Paul Berry2013-09-113-0/+34
| | | | | | | | | This information will be useful in the i965 back end, since we can save some compilation effort if we know from the outset that the shader never calls EndPrimitive(). Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* i965/gs: Add a state atom to set up geometry shader state.Paul Berry2013-09-116-33/+156
| | | | | | | | | | | | v2: Do not attempt to share the code that uploads 3DSTATE_BINDING_TABLE_POINTERS_GS, 3DSTATE_SAMPLER_STATE_POINTERS_GS, or 3DSTATE_GS with VS. Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> v3: Add _NEW_TRANSFORM to gen7_gs_state. Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* i965/gen7: Extract a function for setting up a shader stage's constants.Paul Berry2013-09-112-25/+42
| | | | | | | | This will allow us to reuse some code when setting up the geometry shader stage. Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* wayland-egl.pc requires wayland-client.pc.Torsten Duwe2013-09-111-0/+1
| | | | | | | | | Mesa provides the wayland-egl libs and the pkgconfig file, but the headers originate from the wayland package. Ensure everything matches, by requiring application builds to look at the wayland headers as well. Signed-off-by: Torsten Duwe <duwe@suse.de> Signed-off-by: Johannes Obermayr <johannesobermayr@gmx.de>
* st/gbm: Add $(WAYLAND_CFLAGS) for HAVE_EGL_PLATFORM_WAYLAND.Johannes Obermayr2013-09-111-0/+1
|
* st/dri: do not create a new context for msaa copyMaarten Lankhorst2013-09-1112-33/+34
| | | | | | | | | | | | | | | | Commit b77316ad7594f st/dri: always copy new DRI front and back buffers to corresponding MSAA buffers introduced creating a pipe_context for every call to validate, which is not required because the callers have a context anyway. Only exception is egl_g3d_create_pbuffer_from_client_buffer, can someone test if it still works with NULL passed as context for validate? From examining the code I believe it does, but I didn't thoroughly test it. Signed-off-by: Maarten Lankhorst <maarten.lankhorst@canonical.com> Cc: 9.2 <mesa-stable@lists.freedesktop.org> Reviewed-by: Marek Olšák <marek.olsak@amd.com>
* i965: Add an assertion that writemask != NULL for non-ARFs.Kenneth Graunke2013-09-101-0/+2
| | | | | | | | | | | | | | | | We've observed GPU hangs on Ivybridge from the following instruction: mov(8) g115<1>.F 0D { align16 WE_normal NoDDChk 1Q }; There should be no reason to ever set the writemask on a destination register to zero, except for perhaps the ARF NULL register. This patch adds an assertion to enforce this for non-ARF registers. Excluding ARFs is conservative yet should still catch the majority of mistakes. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Chris Forbes <chrisf@ijw.co.nz>
* i965/vec4: Only zero out unused message components when there are any.Kenneth Graunke2013-09-101-2/+4
| | | | | | | | | | | | | | | | Otherwise, coordinates with four components would result in a MOV with a destination writemask that has no channels enabled: mov(8) g115<1>.F 0D { align16 WE_normal NoDDChk 1Q }; At best, this is stupid: we emit code that shouldn't do anything. Worse, it apparently causes GPU hangs (observable with Chris's textureGather test on CubeArrays.) Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Chris Forbes <chrisf@ijw.co.nz> Reviewed-by: Ian Romanick <idr@freedesktop.org> Cc: mesa-stable@lists.freedesktop.org
* i965/vec4: Simplify the computation of coord_mask and zero_mask.Kenneth Graunke2013-09-101-5/+2
| | | | | | | | | We can easily compute these without loops, resulting in simpler and shorter code. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Suggested-by: Ian Romanick <ian.d.romanick@intel.com> Reviewed-by: Chris Forbes <chrisf@ijw.co.nz>
* mesa: Properly set the fog scale (gl_Fog.scale) to +INF when fog start and ↵Henri Verbeet2013-09-101-2/+1
| | | | | | | | | | | | | | | | | | | | | | | end are equal. This was originally introduced by commit ba47aabc9868b410cdfe3bc8b6d25a44a598cba2, but unfortunately the commit message doesn't go into much detail about why +INF would be a problem here. A similar issue exists for STATE_FOG_PARAMS_OPTIMIZED, but allowing infinity there would potentially introduce NaNs where they shouldn't exist, depending on the values of fog end and the fog coord. Since STATE_FOG_PARAMS_OPTIMIZED is only used for fixed function (including ARB_fragment_program with fog option), and the calculation there probably isn't very stable to begin with when fog start and end are close together, it seems best to just leave it alone. This fixes piglit glsl-fs-fogscale, and a couple of Wine D3D tests. No piglit regressions on Cayman. Signed-off-by: Henri Verbeet <hverbeet@gmail.com> Tested-by: Brian Paul <brianp@vmware.com> Reviewed-by: Brian Paul <brianp@vmware.com>
* mesa: Use correct enum conversion function.Vinson Lee2013-09-101-1/+1
| | | | | | | Fixes "Mixing enum types" defect reported by Coverity. Signed-off-by: Vinson Lee <vlee@freedesktop.org> Reviewed-by: Brian Paul <brianp@vmware.com>
* mesa: Ensure gl_sync_object is fully initialized.Vinson Lee2013-09-101-1/+1
| | | | | | | | | | | | 278372b47e4db8a022d57f60302eec74819e9341 added the uninitialized pointer field gl_sync_object:Label. A free of this pointer, added in commit 6d8dd59cf53d2f47b817d79204a52bb3a46e8c77, resulted in a crash. This patch fixes piglit ARB_sync regressions with swrast introduced by 6d8dd59cf53d2f47b817d79204a52bb3a46e8c77. Signed-off-by: Vinson Lee <vlee@freedesktop.org> Reviewed-by: Brian Paul <brianp@vmware.com>
* radeonsi: Add parentheses around '|' operands.Vinson Lee2013-09-101-1/+1
| | | | | | | | | | | | | | Fixes GCC parentheses warning. r600_texture.c: In function 'si_texture_create': r600_texture.c:518:20: warning: suggest parentheses around arithmetic in operand of '|' [-Wparentheses] !(templ->bind & PIPE_BIND_CURSOR | PIPE_BIND_LINEAR)) { ^ Fixes "Wrong operator used" defect reported by Coverity. Signed-off-by: Vinson Lee <vlee@freedesktop.org> Reviewed-by: Marek Olšák <marek.olsak@amd.com>
* util: Fix unmatched parenthesis.Vinson Lee2013-09-101-1/+1
| | | | | | | | | Fixes MSVC build error introduced with commit 923d3467147dd301d94ed3e6b41295fb2bcd6f47. src\gallium\auxiliary\util\u_cpu_detect.c(286) : fatal error C1012: unmatched parenthesis : missing '(' Signed-off-by: Vinson Lee <vlee@freedesktop.org>
* util: don't use _fxsave() with MSVC 2010 or olderBrian Paul2013-09-102-1/+8
| | | | | | And update _MSC_VER comments in p_config.h Reviewed-by: Roland Scheidegger <sroland@vmware.com>
* glsl: Add missing va_end in builtin_builder::add_function.Vinson Lee2013-09-101-0/+1
| | | | | | | Fixes "Missing varargs init or cleanup" defect reported by Coverity. Signed-off-by: Vinson Lee <vlee@freedesktop.org> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* glsl: Initialize builtin_builder member variables.Vinson Lee2013-09-101-0/+3
| | | | | | | Fixes "Uninitialized pointer field" defect reported by Coverity. Signed-off-by: Vinson Lee <vlee@freedesktop.org> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* glsl: fix variadic macro for MSVCBrian Paul2013-09-091-2/+2
| | | | | | MSVC doesn't accept the rest... syntax. Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* glsl: remove struct keyword from ir_variable declarationsBrian Paul2013-09-091-4/+4
| | | | | | To silence MSVC warnings. Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
* Revert "i965/vec4: Only zero out unused message components when there are any."Kenneth Graunke2013-09-091-4/+2
| | | | | | This reverts commit 6c3db2167c64ecf2366862f15f8e2d4a91f1028c, which I accidentally pushed along with other code. A better version of the fix will be committed later.
* i965: Allow immediates to be folded into logical and shift instructions.Matt Turner2013-09-092-0/+22
| | | | | | | | These instructions will be used with immediate arguments in the upcoming ldexp lowering pass and frexp implementation. v2: Add vec4 support as well. Reviewed-by: Paul Berry <stereotype441@gmail.com>
* i965: Enable MESA_shader_integer_mix.Matt Turner2013-09-091-0/+1
| | | | | Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
* glsl: Implement MESA_shader_integer_mix extension.Matt Turner2013-09-096-8/+41
| | | | | | | Because why doesn't GLSL allow you to do this already? Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
* glsl: Use conditional-select in mix().Matt Turner2013-09-091-8/+8
| | | | | Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
* i965: Add support for ir_triop_csel.Matt Turner2013-09-093-0/+13
| | | | | Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
* glsl: Add conditional-select IR.Matt Turner2013-09-098-0/+38
| | | | | | | | | | | It's a ?: that operates per-component on vectors. Will be used in upcoming lowering pass for ldexp and the implementation of frexp. csel(selector, a, b): per-component result = selector ? a : b Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
* glsl: Rename ir_function_signature::builtin_info to builtin_avail.Kenneth Graunke2013-09-093-7/+7
| | | | | | | | | | | | builtin_info was originally going to be a structure containing a bunch of information, but after various rewrites, it turned into a boolean availability predicate. builtin_avail is a better name than builtin_info, since it doesn't store any information other than availability. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Add missing type inference for ir_binop_bfm.Kenneth Graunke2013-09-091-0/+1
| | | | | | | | Matt noticed that this was missing. Nothing uses this currently. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Delete old built-in function generation code.Kenneth Graunke2013-09-09135-11595/+0
| | | | | | | | None of this is used anymore. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Acked-by: Paul Berry <stereotype441@gmail.com>
* glsl: Remove builtin_compiler from the build system.Kenneth Graunke2013-09-099-252/+23
| | | | | | | | | We don't actually use anything from builtin_function.cpp, so we don't need to generate it anymore. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Acked-by: Paul Berry <stereotype441@gmail.com>
* glsl: Switch to the new built-in function module.Kenneth Graunke2013-09-093-29/+4
| | | | | | | | All built-ins are now handled by the new code; the old system is dead. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Write a new built-in function module.Kenneth Graunke2013-09-093-0/+3528
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This creates a new replacement for the existing built-in function code. The new module lives in builtin_functions.cpp (not builtin_function.cpp) and exists in parallel with the existing system. It isn't used yet. The new built-in function code takes a significantly different approach: Instead of implementing built-ins via printed IR, build time scripts, and run time parsing, we now implement them directly in C++, using ir_builder. This translates to faster load times, and a much less complex build system. It also takes a different approach to built-in availability: each signature now stores a boolean predicate, which makes it easy to construct arbitrary expressions based on _mesa_glsl_parse_state's fields. This is much more flexible than the old system, and also easier to use. Built-ins are also now stored in a single gl_shader object, rather than being spread out across a number of shaders that need to be linked. When searching for a matching prototype, we simply consult the availability predicate. This also simplifies the code. v2: Incorporate Matt Turner's feedback: use the new fma() function rather than expr(). Don't expose textureQueryLOD() in GLSL 4.00 (since it was renamed to textureQueryLod()). Also correct some #undefs. v3: Incorporate Paul Berry's feedback: rename legacy to compatibility; add comments to explain a few things; fix uvec availability; include shaderobj.h instead of repeating the _mesa_new_shader prototype. v4: Fix lack of TEX_PROJECT on textureProjGrad[Offset] (caught by oglc). Add an out_var convenience function (more feedback by Matt Turner). v5: Rework availability predicates for Lod functions. They were broken. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Enthusiastically-acked-by: Paul Berry <stereotype441@gmail.com>
* glsl: Add optional parameters to the ir_factory constructor.Kenneth Graunke2013-09-091-3/+3
| | | | | | | | | | | | | | Each ir_factory needs an instruction list and memory context in order to be useful. Rather than creating an object and manually assigning these, we can just use optional parameters in the constructor. This makes it possible to create a ready-to-use factory in one line: ir_factory body(&sig->body, mem_ctx); Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Add IR builder shortcuts for a bunch of random opcodes.Kenneth Graunke2013-09-092-0/+94
| | | | | | | | | | | | | | | Adding new convenience emitters makes it easier to generate IR involving these opcodes. bitfield_insert is particularly useful, since there is no expr() for quadops. v2: Add fma() and rename lrp() operands to x/y/a to match the GLSL specification (suggested by Matt Turner). Fix whitespace issues. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Expose IR builder support for arbitrary swizzling.Kenneth Graunke2013-09-091-0/+1
| | | | | | | | | | | | | | | | | IR builder already offers a lot of swizzling functions, such as swizzle_xxxx, swizzle_z, or swizzle_for_size. The swizzle_xxxx style is convenient if you statically know which components you want. swizzle_for_size is great if you want to select the first few components. However, if you want to select components based on, say, a loop counter, none of those are sufficient. IR builder actually already had support for arbitrary swizzling, but didn't expose it. This patch exposes that API. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Add a new ir_builder::dotlike() function.Kenneth Graunke2013-09-092-0/+12
| | | | | | | | | | | | dotlike() uses ir_binop_mul for scalars, and ir_binop_dot for vectors. When generating built-in functions, we often want to use regular multiply for scalar signatures, and dot() for vector signatures. ir_binop_dot only works on vectors, so we have to switch opcodes, even if the code is otherwise identical. dotlike() makes this easy. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Add IR builder support for generating return statements.Kenneth Graunke2013-09-092-0/+9
| | | | | | | | | We use "ret" as the function name since "return" is a C++ keyword, and "ir_return" is already a class name. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Add IR builder support for conditional assignments.Kenneth Graunke2013-09-092-2/+17
| | | | | | | | | | | | | This adds two new signatures: assign(lhs, rhs, condition, writemask); assign(lhs, rhs, condition); All the other existing APIs still exist. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Add IR builder support for triops.Kenneth Graunke2013-09-092-0/+9
| | | | | | | | | Now that we have the ir_expression constructor that does type inference, this is trivial to do. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Add an ir_expression triop constructor with type inference.Kenneth Graunke2013-09-092-0/+36
| | | | | | | | | | | | We already have ir_expression constructors for unary and binary operations, which automatically infer the type based on the opcode and operand types. These are convenient and also required for ir_builder support. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Add missing type inference support for ARB_gpu_shader5 unops.Kenneth Graunke2013-09-091-0/+4
| | | | | | Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Initialize lod_info in the ir_texture constructor.Kenneth Graunke2013-09-091-0/+1
| | | | | | | | | | This isn't strictly necessary, since creators of ir_texture objects should set LOD when relevant. However, it's nice to have a NULL pointer in case they forget. Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Skip unavailable built-ins when printing out similar candidates.Kenneth Graunke2013-09-091-0/+3
| | | | | | Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>
* glsl: Skip unavailable built-ins when matching signatures.Kenneth Graunke2013-09-091-0/+8
| | | | | | Signed-off-by: Kenneth Graunke <kenneth@whitecape.org> Reviewed-by: Matt Turner <mattst88@gmail.com> Reviewed-by: Paul Berry <stereotype441@gmail.com>